Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: mysql_connect(): Headers and client library minor version mismatch. Headers:50562 Library:100020 in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: Cannot modify header information - headers already sent by (output started at /home/www/novacisko.cz/subdomains/bredy/init.php:11) in /home/www/novacisko.cz/subdomains/bredy/index.php on line 38
Jak provést operaci až po příkazu return - Bredyho blog - Ondřej Novák
Bredyho blog - Ondřej Novák

Jak provést operaci až po příkazu return

Pokud optimalizujeme kód tak, abychom mohli využít výhod vracení objektu z funkce, narazíme občas na problém, kterak provést některé operace až po provedení příkazu return


V článku Vracíme z funkce objekty byl popsán mechanismus vracení objektu z funkce, pokud návratová hodnota je předávána jako hodnota a nikoliv jako ukazatel nebo reference. Dokázali jsme si, že se lze úplně vyhnout kopírování a přiřazení a funkce je schopná zkonstruovat výsledek přímo v cílovém kontextu.

Pro optimalizaci na straně volaného provádíme konstrukci návratové hodnoty přímo voláním konstruktory, čímž se vyhneme použití kopírovacího konstruktoru

return Object(parametry);

namísto

Object x(parametry);
return x; //neoptimální: použití kopírovacího konstruktoru

Zapomeňme nyní na výhody některých překladačů, které umí poznat, že někde existuje proměnná, která se nakonec použije jako návratová hodnota a eliminují použití kopírovacího konstruktoru.

Občas se stane, že potřebujeme provést ještě nějaké další operace "po returnu", případně musíme objekt zkonstruovat dříve než úplně na konci. Vypadá to, že tady si už nepolepšíme

State setState(const State &newState) {
State prevState = curState;
curState = newState;
return prevState;
}

Tohle je nejtypičtější ukázka. Máme proměnnou typu State obsahující nějaký stav objektu a přejeme si, aby funkce setState při změně stavu vrátila předchozí stav. Když se podíváme do téhle krátké funkce, napočítáme dva kopírovací konstruktory a jeden operátor přiřazení. Jeden kopírovací konstruktor je tam zbytečný, ale protože musíme nastavit nový stav až po konstrukci návratové hodnoty, zdá se, že nemám jiný způsob, jak to zapsat.

On by se ale jeden způsob našel, sice vypadá dost šíleně, ale funguje.

State setState(const State &newState) {

class ModifyState {
public:
State &curState;
const State &newState;
ModifyState(State &curState,const State &newState)
:curState(curState),newState(newState) {}
~ModifyState() {curState = newState;}
};

ModifyState modSt(curState,newState);
return curState;
}

V včem je celý fígl? Nejprve zde vidíme třídu uvnitř funkce. Tohle C++ umožňuje. Vytvoříme si privátní třídu viditelnou jen v této funkci. Ta bude napsaná na míru tomu, co potřebujeme. Tou operací, která se má provést až "po returnu" je přiřazení nového stavu do proměnné curState. Nejprve se ale zkonstruuje návratová hodnota a to vlastním returnem. Destruktor třídy ModifyState se vyvolá až "po returnu". V tu chvíli už můžeme curState měnit, protože návratová hodnota již byla zkonstruováná.

Možná si řeknete, že pro jeden přesun navíc se svět nezboří a počítače jsou dneska rychlé. Kdo by honil pár taktů. Tak si ale představte, že píšete nějaký univerzální kontejner, který má být schopen zpracovat jako jednotlivé bajty, tak objekty, které zaberou půl giga paměti. A nebo, zpracovávat obrovské množství malých objektů. Garantuji vám, že dvojnásobný dataflow při velkých přesunech je znát. Má se přenést 100MB(GB,TB) nebo 200MB(GB,TB)? Tolik totiž může vygenerovat jeden kopírovací konstruktor navíc.

vytvořeno: 24.8.2009 13:05:13, změněno: 24.8.2009 13:05:13
Jsou informace v článku pro Vás užitečné?
  • (4)
  • (0)
  • (0)
  • (0)
  • (4)
Nick nebo OpenID
Vzkaz
 
28.8.2009 01:12:17

Ondra openid

Díky za upozornění, už jsem to opravil (je zajímavé, že v textu je to správně. Pravděpodobně můj oblíbeny copy&paste bug)
27.8.2009 21:18:42

Raději Nick

A ta proměnná prevState v poslední ukázce kódu se najednou vzala kde :-)?

Podobné články

Možnosti "DOSového" příkazu FOR

Příkaz FOR byl v DOSu použit pro vykonávání jednoho příkazu na blok souborů. Tento příkaz však umí mnoho, i když se to moc neví.

Multiple Interface a Instance Factory

Používáme-li v C++ dědičnost a polymorfizmus, často řešíme problém, jak psát operace nad objekty, jejiž implementace se liší podle typu potomka, bez toho aniž bysme zasáhli do Base třídy.

Vracíme z funkce objekty

Podívejme se blížeji na to, jakým způsobem je implementováno vracení výsledku z volání funkcí. Zboříme při tom všelijaké mýty

Tanečky na obecném poli (GenericArray)

Jak sloučit dvě pole, aniž by bylo třeba alokovat jediný bajt? Jak smazat dvě hodnoty z prostřed pole, aniž by se muselo pole fyzicky posouvat? Jak vyzvednout subpole? Jak přerovnat pole bez fyzického přesunu prvku?

Jak sdílet prostředky (resources) v C++

Nemnohokrát jsem řešil v programech psaných v C++, jak sdílet prostředky (resources), jinými slovy, jak zajistit, že jedinečné prostředky budou uvolňovány až v okamžiku, kdy je nikdo nepotřebuje. Podívejme se na jednoduché řešení.
Reklama: