Lebensdauer eines Objekts und Ressourcenverwaltung modernes (C++)
Im Gegensatz zu verwalteten Sprachen nicht C++ Garbagecollection (GC), Nein länger-verwendeten Speicherressourcen automatisch frei, wie ein Programm ausgeführt wird.In C++ ist Ressourcenmanagement Objektlebensdauer direkt verwandt.Dieses Dokument beschreibt die Faktoren, die Objektlebensdauer in C++ und deren Management zu beeinflussen.
C++ keinen GC, vor allem, weil es nicht genügend Speicherressourcen nicht verarbeitet.Deterministische Destruktoren wie in C++ können nur Speicher und nicht-Speicher-Ressourcen gleichermaßen behandeln.GC hat auch andere Probleme, wie die höheren Overhead im Speicher und CPU-Verbrauch und Ort.Aber Universalität ist ein grundlegendes Problem, das durch clevere Optimierungen nicht gemindert werden kann.
Konzepte
Eine wichtige Sache in Objektlebensdauer Management ist die Kapselung – wer ein Objekt verwenden, ist nicht wissen, was die Ressourcen, die Objekt besitzt, oder wie sie loswerden oder sogar, ob sie alle Ressourcen auf allen besitzt.Es muss nur das Objekt zu zerstören.Die C++-Kernsprache ist so konzipiert, dass Objekte, d. h. die korrekten Uhrzeiten zerstört werden als in umgekehrter Reihenfolge der Konstruktion Blöcke verlassen.Wenn ein Objekt zerstört wird, werden die Grundlagen und die Mitglieder in einer bestimmten Reihenfolge zerstört.Die Sprache zerstört automatisch Objekte, wenn Sie spezielle Dinge wie Heapreservierung oder neue Platzierung tun.Beispielsweise intelligente Zeiger wie unique_ptr und shared_ptr, und wie der Container (Standard Template Library, STL) vector, kapseln new/delete und new[]/delete[] in Objekten, die Klassen besitzen Destruktoren.Deshalb ist es so wichtig, intelligente Zeiger und STL-Containern verwendet.
Ein weiteres wichtiges Konzept in der Lebensdauerverwaltung: Destruktoren.Destruktoren kapseln die Freigabe der Ressource.(Das häufig verwendete mnemonische Zeichen ist RRID, Ressource Release ist Zerstörung.) Eine Ressource ist etwas, das Sie von "System" und später wieder zu geben.Speicher ist die am häufigsten verwendete Ressource, aber es gibt auch, Dateien, Sockets, Texturen und andere nicht-Speicher-Ressourcen. "Besitzen"eine Ressource bedeutet, Sie können es bei Bedarf aber auch um es zu lösen, wenn Sie damit fertig sind.Wenn ein Objekt zerstört wird, gibt der Destruktor Ressourcen frei, die es im Besitz.
Das endgültige Konzept ist die DAG (Directed azyklisch Graph).Die Struktur von Eigentum in einem Programm bildet eine DAG.Kein Objekt kann selbst besitzen – das ist nicht nur unmöglich, aber auch grundsätzlich bedeutungslos.Aber zwei Objekte können den Besitz eines dritten Objekts.Mehrere Arten von Links in einer DAG wie folgt möglich sind: A ist ein Mitglied von B (B besitzt A), C speichert ein vector<D> (C besitzt jedes Element D), E-Stores ein shared_ptr<F> (E teilt den Besitz von F, möglicherweise mit anderen Objekten), und so weiter.Solange es keine Zyklen gibt und jedes Glied in der DAG durch ein Objekt dargestellt wird, hat einen Destruktor (anstelle von einem unformatierten Zeiger, Handle und andere Mechanismen), dann Ressourcenverluste sind ausgeschlossen, da die Sprache, die sie verhindert.Ressourcen werden freigegeben, sobald sie nicht mehr benötigt werden, ohne einen Garbage Collector ausgeführt.Die Lebensdauer tracking ist für Stack-Rahmen, Basen, Mitglieder und ähnliche Fälle Overhead frei und kostengünstig shared_ptr.
Heap-Lebensdauer
Für Heap-Objektlebensdauer verwenden intelligente Zeiger.Verwendung shared_ptr und make_shared als Standardzeiger und Zuweisung.Verwendung weak_ptr brechen Zyklen, Zwischenspeicherung und beobachten Objekte ohne zu beeinflussen oder etwas über ihre Lebensdauer vorausgesetzt.
void func() {
auto p = make_shared<widget>(); // no leak, and exception safe
...
p->draw();
} // no delete required, out-of-scope triggers smart pointer destructor
Verwendung unique_ptr für eindeutige Identifikation, z. B. in der Pimpl Idiom.(Siehe Pimpl für Kompilierzeitkapselung modernes (C++).) Stellen eine unique_ptr die primäre Zielgruppe für alle expliziten new Ausdrücke.
unique_ptr<widget> p(new widget());
Sie können für nicht-Besitz und Beobachtung Rawzeiger verwenden.Ein Zeiger nicht besitzen kann hängen, aber es kann nicht auslaufen.
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(...) ); }
Wenn Performance-Optimierung erforderlich ist, müssen Sie möglicherweise verwenden Sie gekapseltes Zeiger und explizite Aufrufe zu löschen.Ein Beispiel ist beim Implementieren Ihrer eigenen Low-Level-Datenstruktur.
Stapelbasierte Lebensdauer
In modernen C++ stackbasierte Geltungsbereich ist eine leistungsstarke Möglichkeit stabilen Code zu schreiben, da es automatische kombiniert Stack Lebensdauer und Daten Mitglied Lebensdauer mit hoher Effizienz – Lebensdauer tracking ist im wesentlichen Mehraufwand.Heap Objektlebensdauer kann fleißig Manuelles Management erforderlich und die Quelle der Ressourcenverluste und Ineffizienz, vor allem, wenn Sie mit Rawzeiger arbeiten.Betrachten Sie diesen Code, der Stapel Bereich veranschaulicht:
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(); }"
Lebensdauer der statischen sparsam verwenden (globale statische, lokale statische Funktion) da Probleme auftreten können.Was passiert, wenn der Konstruktor eines globalen Objekts eine Ausnahme auslöst?In der Regel die app Fehler in einer Weise, die schwierig zu debuggen sein kann.Bauauftrag ist problematisch für die Lebensdauer der statischen Objekte, und nicht sicher.Objekterstellung ist nicht nur ein Problem Zerstörungsreihenfolge kann komplex sein, insbesondere bei der Polymorphie beteiligt ist.Auch wenn Sie das Objekt oder eine Variable ist nicht polymorph und nicht komplexen Konstruktion/Zerstörung, Bestellung, bleibt das Problem der Parallelität threadsicher.Eine Multithread-Anwendung kann nicht sicher die Daten in statische Objekte ändern, ohne lokalen Threadspeicher, Ressourcensperren und andere besonderen Vorsichtsmaßnahmen.