Skip to main content

Jazyky C a C++ (Ukázka, strana 99)

Page 1

❚ P ři jakékoli manipulaci s objektem, na který ukazuje restringovaný ukazatel, bychom měli používat pouze tento ukazatel a hodnotu tohoto ukazatele bychom neměli přiřazovat jiným ukazatelům. ❚ R estringovaný ukazatel by měl v jednom bloku ukazovat stále na stejný objekt. ❚ K objektu, který se v daném bloku nemění, lze přistupovat i prostřednictvím několika restringovaných ukazatelů. ❚ K dyž uvedená pravidla porušíme, může se program chovat nedefinovaným způsobem (při optimalizaci může vzniknout nesprávný kód). ❚ P oužijeme-li modifikátor restrict v deklaraci parametrů funkce f(), umožníme tím překladači provést efektivní analýzu závislostí funkce f(), aniž by musel zkoumat všechna její volání v programu, a podle toho bude moci optimalizovat její kód. Toto zkoumání se však přenáší na bedra programátora, který si musí při každém volání uvědomit, zda použité parametry nepovedou k nedefinovanému chování.

PŘÍKLAD Na úrovni souboru jsme deklarovali ukazatele int * restrict a; int * restrict b; int * c;

Tím tvrdíme, že přistoupíme-li k nějakému objektu prostřednictvím jednoho z těchto ukazatelů, a je-li tento objekt někde v programu měněn, nebudeme k němu přistupovat prostřednictvím druhého z nich.

PŘÍKLAD Použijeme-li modifikátor restrict v deklaraci parametrů funkce následujícím způsobem, void f(int n, int * restrict p, int * restrict q) { while(n-- > 0) *p++ = *q++; }

zavazujeme se tím, že při žádném volání této funkce nebude ukazatel p přistupovat ke stejnému objektu jako ukazatel q. Tento příklad ukazuje obě protikladné stránky používání modifikátoru restrict. Například volání extern int A[100]; f(50, A, A+50); // OK

je v pořádku, zatímco volání f(50, A, A+1); // NEDEFINOVANÉ CHOVÁNÍ

může způsobit nedefinované chování programu. Problém je v tom, že s prvky A[1] až A[49] pole A pracujeme v rámci jediného volání funkce f() jak pomocí restringovaného ukazatele p, tak i pomocí restringovaného ukazatele q.

98  Jazyky C a C++ Ukázka elektronické knihy, UID: KOS180894


PŘÍKLAD Definujeme-li funkci void h(int n, int * restrict p, int * restrict q, int * restrict r) { int i; for(i = 0; i < n; i++) p[i] = q[i]+r[i]; } je volání

h(100, a, b, b);

// OK

zcela v pořádku, pokud a a b ukazují na různá pole. Pole b se totiž ve funkci h() nemění, a proto nevadí, že k němu přistupujeme prostřednictvím dvou různých restringovaných ukazatelů.

5.3 Reference (jen v C++) Na reference (odkazy) se můžeme dívat jako na alias – jiné jméno – pro již existující proměnnou (l-hodnotu). To znamená, že veškeré operace s referenční proměnnou znamenají operace s proměnnou, na kterou reference odkazuje („odkazovanou“ proměnnou). V C++0x máme dispozici také reference na r-hodnotu. Reference mohou v C++ odkazovat také na funkce. Reference deklarujeme podobně jako ukazatele, pouze místo znaku * použijeme znak & (pro referenci na l-hodnotu) nebo && (pro referenci na r-hodnotu, jen v C++0x). Nejčastěji je využíváme k předávání parametrů funkcí odkazem (viz kapitola 10.2.2). To se hodí např. v případě, že funkce přímo mění předávané proměnné. Reference také mohou zabránit kopírování velkých datových struktur a tak zrychlit běh programu. Použití referencí také zlepšuje čitelnost programu, neboť pak není třeba dereferencovat ukazatele v tělech funkcí. Zjednodušený popis deklarace reference je: deklarace reference (zjednodušeno): • t yp & jméno ; • t yp && jméno ; // Jen C++0x • t yp & jméno = inicializátor • t yp && jméno = inicializátor ; // Jen C++0x ❚ P rvní dvě možnosti představují deklaraci reference, poslední dvě představují definici. ❚ T yp je datový typ objektu, na který reference odkazuje. ❚ & říká, že tuto proměnnou deklarujeme jako referenci na l-hodnotu; && říká, že deklarujeme referenci na r-hodnotu (viz kapitola 5.3.3). ❚ J méno je identifikátor deklarované referenční proměnné. ❚ I nicializátor je výraz představující l-hodnotu nebo funkci (v případě reference na l-hodnotu) nebo výraz (v případě reference na r-hodnotu), na kterou bude deklarovaná reference

Ukazatele, pole a reference  99 Ukázka elektronické knihy, UID: KOS180894


odkazovat. Referenci na r-hodnotu nelze inicializovat l-hodnotou. (Podrobně o deklaraci v kapitole 6.1). ❚ F unkce mohou vracet výsledek pomocí reference.

PŘÍKLAD #include <iostream> using namespace std; int promenna; int& referencni_promenna = promenna; void func(int& ref); int main() { int prom; // Deklarace proměnné int& prom_kopie = prom;// Referenční proměnná prom = 29; cout << prom; // Vypíše 29 cout << prom_kopie; // Vypíše 29 prom_kopie = 31; cout << prom; // Vypíše 31 cout << prom_kopie; // Vypíše 31 } ❚ R eferenční proměnná musí být v definici inicializována. Inicializace reference na l-hodnotu říká, na kterou proměnnou nebo funkci bude reference odkazovat. (Veškeré operace s referencí jsou pak operace s touto proměnnou, resp. funkcí, uvedenou v inicializaci.) ❚ R eference explicitně neinicializujeme: ■ V deklaraci, která není definicí (extern). ■ V deklaraci parametru funkce (předání parametru zde hraje roli inicializace). ■ Jestliže se jedná o prvek třídy (pak ji inicializujeme v inicializační části konstruktoru). ■ Při vracení výsledku funkce odkazem. Hodnota uvedená v příkazu return zde slouží jako inicializátor. ❚ R eferenční proměnná odkazuje po celou dobu své existence stále na stejnou proměnnou. Nelze ji „přepnout“ na jinou proměnnou! ❚ D atový typ referenční proměnné (reference na l-hodnotu) a datový typ proměnné použité k inicializaci musí být stejný – kromě případu, kdy inicializujeme referenci na objektový typ T instancí přístupného jednoznačného potomka typu T, instancí typu, který lze implicitní konverzí převést na T nebo na potomka typu T, nebo když inicializujeme konstantní referenci (viz kapitola 5.3.2). (Tradiční objektové pravidlo: Potomek může zastoupit předka.) ❚ N elze definovat ukazatele na reference. ❚ N elze vytvářet pole referencí. ❚ N elze definovat reference na reference. ❚ R eference nemohou být typu void. ❚ P omocí referencí lze obejít pravidlo, že funkce nesmějí vracet pole nebo funkce. Mohou totiž vracet reference na pole a reference na funkce.

100  Jazyky C a C++ Ukázka elektronické knihy, UID: KOS180894


Turn static files into dynamic content formats.

Create a flipbook
Jazyky C a C++ (Ukázka, strana 99) by Kosmas-CZ - Issuu