Metody vracení hodnot z funkce
C++ 11

image_printTisk

DO POKROČILÝCH ASI

Tento článek pojednává o způsobech vracení hodnot z funkcí. Jsou to stejné způsoby, o kterých je psáno ve článku předchozím, tedy vracení hodnotou nebo vracení odkazem. U vracení hodnot odkazem lze opět buď použít ukazatel, nebo referenci. Je důležité mít ale na vědomí, že u vracení hodnot odkazem panují určitá omezení.

Způsob vracení hodnotou byl, je a bude na těchto stránkách používán mnohokrát. Stačí uvést před název funkce příslušný datový typ a vrátit hodnotu za pomoci příkazu return. Zabývejme se spíše otázkou, jak vracet hodnoty odkazem. “Pod kapotou” to opět funguje tak, že v binárním kódu se nevrací hodnota jako taková, ale adresa v paměti, kde je hodnota uložena. Ukažme si opět na příkladu, jak vypadá syntaktický zápis obou způsobů, tedy za pomoci ukazatele i reference.

#include <iostream>
using namespace std;

int pole[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int* getValuePtr(int index) {
    return pole + index;
}

int& getValueRef(int index) {
    return pole[index];
}

int main() {
    cout << "Pole[3] je " << *getValuePtr(3) << endl;
    cout << "Pole[7] je " << getValueRef(7) << endl;

    return 0;
}
Unable to connect to the JDoodle service.

Příklad začíná definicí globálního pole. Za ním následuje funkce getValuePtr vracející hodnotu položky v poli za pomocí ukazatele a po té je definována funkce getValuePtr zastávající tutéž funkce, ale za pomocí reference. Funkce main pak už jen provádí výpis hodnot položek pole na příslušných pozicích na textovou konzoli.

Při vracení hodnot z funkcí odkazem je se třeba mít ale na pozoru. Nelze vracet odkazy na klasické lokální proměnné. V případě vracení hodnoty pomocí reference naštěstí překladač ohlásí syntaktickou chybu kódu, v případě použití ukazatele vše v tichosti projde překladačem, ale pak ve výsledném binárním kódu vznikne kritická chyba, která se bude jen těžko hledat. Příčinou tohoto chování je, že po opuštění těla funkce se uvolní také paměťový prostor, kam by ukazovala adresa vrácená funkcí. Dá se tedy říci, že takto vrácená adresa ukazuje na již neexistující či nevalidní úsek paměti, což je zdrojem mnoha chyb. Ukažme si vše na příkladu.

// V případě vracení pomocí ukazatele překladač nic neohlásí, ale vznikne v binárním kódu vážná chyba
int* getValuePtr(int index) {
    int pole[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    return pole + index;
}

// Tuto funkci překladač nepřeloží a ohlásí syntaktickou chybu
int& getValueRef(int index) {
    int pole[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    return pole[index];
}

Přece je ale jen možné předchozí příklad pomocí jazykových prostředků C++ upravit tak, aby fungoval. Napřed je nutné si ale vysvětlit rozdíl mezi automatickými a statickými proměnnými. Automatická proměnná je druh proměnné, kterou jsme doposud používali. Je to proměnná, jejíž platnost je omezena nějakým blokem příkazů a jejíž hodnota “nepřežije” opuštění daného bloku. Naproti tomu, pokud k deklaraci lokální proměnné je přidáno klíčové slovo static, takováto proměnná se stává proměnnou statickou, což znamená, že její hodnota je uchována i při opuštění funkce či jiného bloku příkazů. Po návratu do funkce hodnota statické proměnné je stejná, jako po posledním ukončení daného bloku příkazů, kde je deklarována. Ukažme si předchozí příklad za použití statických proměnných.

#include <iostream>
using namespace std;

int* getValuePtr(int index) {
    static int pole[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    return pole + index;
}

int& getValueRef(int index) {
    static int pole[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    return pole[index];
}

int main() {
    cout << "Pole[3] je " << *getValuePtr(3) << endl;
    cout << "Pole[7] je " << getValueRef(7) << endl;

    return 0;
}
Unable to connect to the JDoodle service.

Na závěr si rozšíříme pochopení, co znamenají v C++ pojmy L-hodnota R-hodnota. V předchozím článku byla zmíněná definice L-hodnoty, že to je výraz, který může stát na levé straně přiřazovacího operátoru. Pravdou je, že v C++ může stát L-hodnota i na straně pravé. Definujme L-hodnotu jako výraz, který není v binárním kódu ani tak nositelem hodnoty výrazu jako takové, ale spíše nese adresu v paměti, kde je hodnota uložena. Rozdílné je chování výrazu tohoto druhu podle toho, na jaké straně přiřazovacího operátoru stojí. Pokud na levé, jedná se o zápis na adresu, kterou L-hodnota obsahuje, na straně pravé vrací tento výraz hodnotu uloženou na adrese jímž je nositelem.

R-hodnota na rozdíl od L-hodnoty, je výraz, jehož vyhodnocením vzniká pouze “čistá hodnota”, a může být umístěn pouze na pravé straně operátoru přiřazení. V případě umístění na straně levé překladač ohlásí syntaktickou chybu. Následující příklad demonstruje, jak lze do statického pole uvnitř funkce hodnoty jak ukládat, tak číst.

#include <iostream>
using namespace std;

int& getValueRef(int index) {
    static int pole[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    return pole[index];
}

void printArrayValue(int index) {
    cout << "Hodnota na indexu " << index << " je " << getValueRef(index) << endl;
}

void swapIndexes(int index1, int index2) {
    int tmp = getValueRef(index1);
    getValueRef(index1) = getValueRef(index2);
    getValueRef(index2) = tmp;
}

int main() {
    printArrayValue(3);
    printArrayValue(6);
    
    swapIndexes(3, 6);
    cout << endl;
    
    printArrayValue(3);
    printArrayValue(6);
    
    return 0;
}
Unable to connect to the JDoodle service.
image_printTisk
Metody vracení hodnot z funkce
C++ 11
Ohodnoťte tento článek

Související články

  • Předávání a vracení polí z funkcí DO POKROČILÝCH TÉMAT Tento článek pojednává o práci s poli a funkcemi. Popisuje rozličné metody, jak předat pole jako argument funkci a také jak pole z funkce vrátit. Existují v […]
  • Vícerozměrná pole Tento článek pojednává o vícerozměrných polích v jazyce C++. Seznámíme se s jejich významem, deklarací, inicializací a způsobem zápisu a čtení jejich hodnot. Na závěr článku bude zmíněno, […]
  • Ukazatele na pole V tomto článku si probereme ukazatele na pole. Seznámíme se nejen s ukazateli na pole jednorozměrné, ale i na složitější případ, tedy pole vícerozměrná. Vše si zase samozřejmě uvedeme na […]
  • Aritmetika ukazatelů a pole V tomto článku si vysvětlíme, co je aritmetika ukazatelů. Ukážeme si význam a aplikaci dalších operátorů vztahujících se k ukazatelům a popíšeme si jejich vzájemné vztahy k polím různých […]
  • Ukazatele V tomto článku si představíme nový pojem ukazatel jako proměnnou obsahující adresu na jinou oblast paměti. Seznámíme se dvěma operátory při související s adresací a na závěr si ukážeme, […]
  • Pole v C++ V tomto článku si vysvětlíme nový pojem jazyka C++, a to pole nějakých hodnot. Je to jazykový konstrukt, který slouží k uchování seznamu hodnot nějakého datového typu. Je důležité zmínit, […]