Životní cyklus objektů a správa prostředků (moderní verze jazyka C++)
Na rozdíl od spravované jazyky C++ nemá uvolněné (GC), který automaticky uvolní prostředky ne delší použité paměti při spuštění programu.V jazyce C++ Správa zdrojů přímo souvisí životnost objektu.Tento dokument popisuje faktory, které ovlivňují životnost objektu v jazyce C++ a jeho správa.
C++ nemá GC, především proto, že je nelze zpracovat bez paměťové prostředky.Deterministický destruktory, stejně jako v C++ lze zpracovat pouze prostředky paměti a bez paměti stejně.GC má také další problémy, jako jsou vyšší nároky na paměť a spotřeby procesoru a místo.Ale obecnosti je zásadní problém, který nelze zmírnit až dokonalá optimalizace.
Koncepty
Důležité řízení životnosti objektů je zapouzdření – ten, kdo používá objekt nemá vědět, co vlastní prostředky, které objekt, nebo jak odstranit nebo dokonce zda vlastní zdroje vůbec.Právě je zničení objektu.Základní jazyk C++ umožňuje zajistit, že objekty jsou zničeny, ve správném čase, jako je ukončen bloky, v obráceném pořadí v konstrukci.Po zničení objektu, jsou zničeny jeho základny a členy v určitém pořadí. Jazyk automaticky odstraní objekty, dokud neprovedete zvláštní například přidělení haldy nebo nové umístění. Například inteligentní ukazatele jako unique_ptr a shared_ptr, a jako kontejnery knihovny STL (Standard Template) vector, zapouzdření new/delete a new[]/delete[] v objektech, které mají destruktory.To je důvod, proč je tak důležité použít inteligentní ukazatele a STL kontejnery.
Další důležitou koncepcí v řízení životnosti: destruktory.Destruktory zapouzdřit uvolnění prostředků. (Běžně používaný symbol je RRID zničení je uvolnění prostředků). Prostředek je něco, co můžete získat z "systém" a dát později. Paměť je nejběžnější prostředek, ale jsou také soubory, sokety, textury a dalších prostředků než paměť. "Vlastnictvím" zdroje znamená, že můžete použít, když ji potřebujete, ale máte také uvolnění po dokončení s ním. Po zničení objektu, jeho destruktor uvolní prostředky, které je ve vlastnictví.
Závěrečný pojem je DAG (řízené acyklický graf). Struktura vlastnictví v programu tvoří DAG.Žádný objekt může vlastnit sebe sama – to není pouze nemožné, ale také ve své podstatě bezvýznamné.Ale dva objekty můžete sdílet vlastnictví třetí objekt. Několik druhů odkazy jsou možné v DAG takto: A je členem skupiny B (B vlastní A), C obchody vector<D> (C vlastní každý prvek D), E obchody shared_ptr<F> (E podíly vlastnictví F, případně s jinými objekty), a tak dále. Tak dlouho, dokud nejsou k dispozici žádné cykly a každý odkaz DAG je reprezentována objektem destruktor (místo raw ukazatel úchytu nebo jiným mechanismem), který má pak nedostatku prostředků jsou nemožné, protože nemohou jazyk.Prostředky jsou uvolněny ihned poté, co jste již nepotřebujete, bez uvolňování, systémem.Celoživotní sledování je bez režie pro obor zásobníku, základů, členy a související případy a jsou levné pro shared_ptr.
Doba platnosti založené na haldě
Životnost objektu haldy pomocí inteligentní ukazatele.Použití shared_ptr a make_shared jako výchozí kurzor a přidělování.Použití weak_ptr konec cyklů, ukládání do mezipaměti, a sledovat objekty bez ovlivnění nebo za předpokladu, že nic o jejich životnost.
void func() {
auto p = make_shared<widget>(); // no leak, and exception safe
...
p->draw();
} // no delete required, out-of-scope triggers smart pointer destructor
Použití unique_ptr pro jedinečné vlastnictví, například v pimpl idiomu. (Viz Ukazatel na implementaci pro zapouzdření při kompilaci (moderní verze jazyka C++).) Aby unique_ptr primární cíl všechny explicitní new výrazy.
unique_ptr<widget> p(new widget());
Raw ukazatele můžete použít pro jiné vlastnictví a pozorování.Ukazatel vlastnící mohou dangle, ale nemůže proniknout.
class node {
...
vector<unique_ptr<node>> children; // node owns children
node* parent; // node observes parent, which is not a concern
...
};
node::node() : parent(...) { children.emplace_back(new node(...) ); }
Při optimalizaci výkonu je požadováno, pravděpodobně budete muset použít dobře zapouzdřené vlastnící ukazatele a explicitní volání, které chcete odstranit.Je například při implementaci struktury dat na nižší úrovni.
Životnost zásobníku
V jazyce C++ moderní oboru založené na zásobníku je efektivní způsob, jak psát kód robustní, protože kombinuje automatické životnost zásobníku a životnost dat člen s vysokou účinností – celoživotní sledování je v podstatě bez zatížení.Životnost objektu haldy vyžaduje důslednost ruční řízení a může být zdrojem nedostatku prostředků a nedostatky, zejména při práci s raw ukazatele.Zvažte tento kód, který ukazuje rozsah založené na zásobníku:
class widget {
private:
gadget g; // lifetime automatically tied to enclosing object
public:
void draw();
};
void functionUsingWidget () {
widget w; // lifetime automatically tied to enclosing scope
// constructs w, including the w.g gadget member
…
w.draw();
…
} // automatic destruction and deallocation for w and w.g
// automatic exception safety,
// as if "finally { w.dispose(); w.g.dispose(); }"
Používejte statické životnost opatrně (statické globální, místní statická funkce) vzhledem k tomu, že může dojít k problémům.Co se stane, když konstruktoru globálního objektu vyvolá výjimku?Obvykle aplikace poruch způsobem, který může být obtížné ladit.Stavební zakázky je problematický statický životnosti objektů a není bezpečné souběžnosti.Nejen stavební objekt je problém, zničení objednávka může být složité, zejména pokud se jedná o polymorfismus.I v případě objektu nebo proměnné není polymorfní a nemá složité konstrukce zničení řazení, je stále problém souběžnosti vláken.Více vláknové aplikace nelze bezpečně změnit data v statických objektů bez nutnosti podproces místní úložiště, uzamčení prostředků a jiná zvláštní opatření.
Viz také
Další zdroje
C++ vás vítá zpět (moderní verze jazyka C++)