Frage

Wenn ich einen Destruktor explizit aufrufe ( myObject.~Object() ), stellt mir das sicher, dass das Objekt ordnungsgemäß zerstört wird (alle untergeordneten Destruktoren werden aufgerufen)?

Ok, ein Code:

class Object
{
   virtual ~Object()
   {}
};

class Widget : public Object
{
   virtual ~Widget()
   {}
};

...
Object* aWidget = new Widget(); //allocate and construct
aWidget->~Object(); //destroy and DON'T deallocate

Ich weiß, ich könnte das Objekt einfach löschen, aber ich möchte nicht.Als wichtige Optimierung möchte ich den zugewiesenen Speicher griffbereit halten.

Danke!

War es hilfreich?

Lösung

Die Antwort ist ... fast immer.

Wenn Sie Ihr Objekt einen nicht-virtuellen Destruktor hat, und ist dann untergeordnete Kind-Elemente hinzufügen, die zu befreien müssen ... dann auf dem Objekt Basisklasse die destructor Aufruf nicht die untergeordneten Elemente befreien. Aus diesem Grund sollten Sie immer Destruktoren virtuell deklarieren.

Wir hatten einen interessanten Fall, in dem zwei gemeinsam genutzte Bibliotheken ein Objekt referenziert. Wir änderten die Definition Kind-Objekte hinzufügen, die befreiende benötigt. Wir neu kompiliert die erste gemeinsame Bibliothek, die die Objektdefinition enthalten sind.

Allerdings war die zweite gemeinsame Bibliothek nicht neu kompiliert. Das bedeutet, dass es nicht von der neu hinzugefügten virtuellen Objektdefinition nicht kannte. Löschen des aus der zweiten gemeinsam genutzten Bibliothek aufgerufen einfach frei genannt, und rufen Sie nicht die virtuelle destructor Kette. Ergebnis war ein böser Speicherverlust.

Andere Tipps

Ja. Aber Holy Smokes, sind Sie sicher? Wenn ja würde ich Platzierung new verwenden, um Ihre Widget zu konstruieren. Platzierung new und anschließend die destructor expliziten Aufruf ist ein akzeptabler, wenn ungewöhnlich, Idiom.

Bearbeiten : Betrachten Sie das Zuweisen von Speicher selbst manuell anstatt new mit dem ersten Objekt zuweisen und dann wieder mit seinem Speicher hinterher. Das erlaubt Ihnen die vollständige Kontrolle über den Speicher; könnte man große Stücke auf einmal, zum Beispiel, anstatt Zuweisung eines separaten Speicherblock für jeden Widget zuordnen. Das wäre faire Einsparungen, wenn der Speicher wirklich so eine knappe Ressource ist.

Auch und vielleicht noch wichtiger ist, würden Sie dann tun Platzierung new „normal“ werden, anstatt diese Hybrid regelmäßig new / Platzierung new Lösung. Ich sage nicht, es wird nicht funktionieren, ich sage nur, es ist eine ziemlich, ah, kreativ Lösung Ihres Speicherproblem.

Ja, ein destructor, auch wenn explizit genannt wird, wird seine Subobjekte richtig zerstören.

Wie Sie zu erkennen scheinen, es ist eine seltene Aktion zu tun, aber vielleicht als Teil eines gut getestet und dokumentiert Bibliothek kann es nützlich sein. Aber Dokument (und Profil) ist es da, obwohl es gültig und sicher, jeder Betreuer (einschließlich Sie) werden nie wohl fühlen mit ihm.

Ja wird es rufen alle Kind Destruktoren so wird es funktionieren, wie Sie erwarten.

Der destructor ist nur eine Funktion, nachdem alle, es passiert einfach so, dass es aufgerufen wird, wenn Objekte gelöscht .

Deshalb, wenn Sie diesen Ansatz verwenden, achten Sie auf diese:

#include <iostream>

class A
{
public: 
    A(){};
    ~A()
    {
        std::cout << "OMG" << std::endl;
    }
};

int main()
{
    A* a = new A;
    a->~A();
    delete a;
    return 0;
}

output:
OMG
OMG 

Der Destruktor wird ein zweites Mal aufgerufen, wenn Lösch tatsächlich auf das Objekt aufgerufen wird, wenn Sie also Zeiger in Ihrem destructor löschen, stellen Sie sicher, dass Sie sie auf 0 gesetzt, so dass der zweite die destructor nichts passieren wird, aufgerufen wird (wie ein null-Zeiger zu löschen tut nichts).

Bitte sparen Sie sich einige echte Kopfschmerzen und verwenden Sie die -Boost Objekt-Pool , die wie eine bestehende Implementierung Ihrer Quelle / Senke Muster klingt. Es wird zuteilen große Teile des Gedächtnisses, in Scheiben schneiden in die richtige Größe für Ihr Objekt und bringt sie zu Ihnen (nach dem Konstruktor aufrufen). Wenn Sie Objekte löschen, sie haben ihre destructor genannt und sind für die Weiterverwendung einer verknüpften Liste von Objekten setzen in. Sie wird wachsen und schrumpft automatisch und sorgt dafür, dass Instanzen Ihrer Objekte sind in der Regel im Speicher nahe beieinander sein.

Wenn nichts anderes, es ist ein gutes Beispiel Umsetzung der Platzierung neuer und die explizite Verwendung von Konstrukteuren, die Sie studieren zu können.

Ja.Ein Destruktor ruft alle Member-Destruktoren in LIFO-Reihenfolge auf, dann Basisklassen-Destruktoren, und es gibt keine Möglichkeit dazu verhindern es davon ab, diese Destruktoren aufzurufen*.Der Objektstapel wird garantiert abgewickelt.

Initialisierung und Finalisierung sind in C++ genau von der Speicherzuweisung und -freigabe getrennt, sodass im Sonderfall eine eindeutige Syntax vorliegt, in der der Anwendungsprogrammierer seine Absicht gegenüber dem Compiler zum Ausdruck bringen kann.

Bearbeiten:

  • Ich nehme an, dass man durch den Aufruf von abort() oder longjmp() tatsächlich verhindern könnte, dass die Member- und Basisklassen-Destruktoren ausgeführt werden.

die destructor Lauf nicht freie Speicher durch das Objekt verwendet, zerstört zu werden - der Delete-Operator das tut. Beachten Sie jedoch, dass der Destruktor löschen kann „Kind-Objekte“ und ihr Gedächtnis wird wie üblich befreit werden.

Sie müssen sich auf die Platzierung lesen, neue / löschen, da dies ermöglicht es Ihnen, Speicherzuweisung zu steuern und wenn Konstrukteure / Destruktoren ausgeführt werden.

Sehen Sie hier für eine kleine Info:

http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9

STL-Container tun. In der Tat muss ein STL Allocator ein Verfahren zerstören schaffen, die ein destructor (allcators auch ein ausplanen Verfahren die Speicher freizugeben, die ein Objekt zu halten, verwendet wird) das Objekt aufruft. Allerdings ist die Beratung von Stroustrup ( Die C ++ Programmiersprache 10.4.11) ist

  Hinweis

, dass explizite Aufrufe von Destruktoren ... sollte nach Möglichkeit vermieden werden. Gelegentlich sind sie unerlässlich. ... Es sollte ein Anfänger denken, dreimal, bevor sie eine destructor explizit aufrufen und auch einen erfahrenen Kollegen fragen, bevor dies zu tun.

die destructor Aufruf ist in Ordnung. Allerdings passen sie vom Typ Sie es beim Aufruf sind. Wenn dieser Typ muss nicht (habe erben nicht) einen virtuellen Destruktor, können Sie unerwartetes Verhalten bekommen.

Auch, wie bereits erwähnt, wird der Destruktor keine Speicher frei, aber ich denke, das ist der Grund, warum Sie wollen, dass es manuell nennen an erster Stelle.

Plus, es sei denn, ich irre, manuell den destructor Aufruf ist die einzige Option, die Sie haben, wenn Sie die Platzierung verwendet, um neue den Konstruktor aufzurufen.

Warum es zerstören überhaupt? Schreiben Sie einfach über das Gedächtnis? Sind Sie wollen Logik ordnungsgemäß auszuführen, um die Freigabe Ressourcen zu umgehen? Ich werde mit Nachdruck sagen, dass dies ein Missbrauch der Sprache und nicht eine gute Idee.

Ich würde neue zwingende für die Objekte, die Sie für spezielle Zuweisung und Freigabe Verhalten wollen - schließlich das ist, was es ist. Ein Hybrid-System des normalen neuen und expliziten Aufruf Destruktoren klingt wie ein Rezept für zukünftige Kopfschmerzen. Für den Anfang wird jede Speicherleckerkennungsstrategie weg bekommen geworfen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top