2010-10-18 6 views
9

Der folgende Code kompiliert mit MSVC9.0 läuft und gibt Destructor vier Mal aus, was logisch ist.Objektorientierter Selbstmord oder löschen Sie dies;

#include <iostream> 
class SomeClass 
{ 
public: 
    void CommitSuicide() 
    { 
     delete this; 
    } 
    void Reincarnate() 
    { 
     this->~SomeClass(); 
     new (this) SomeClass; 
    } 
    ~SomeClass() 
    { 
     std::cout << "Destructor\n"; 
    } 
}; 

int main() 
{ 
    SomeClass* p = new SomeClass; 
    p->CommitSuicide(); 
    p = new SomeClass; 
    p->Reincarnate(); 
    p->~SomeClass(); //line 5 
    p->CommitSuicide(); 
} 

Ich denke, die ersten 4 Zeilen Code in Haupt in undefiniertem Verhalten führen nicht (wenn auch nicht ganz sicher über die delete this; Sache). Ich möchte eine Bestätigung oder < Platzhalter für die Bestätigung der Antonym> davon haben. Aber ich habe ernsthafte Zweifel an den Zeilen 5 und 6. Es ist erlaubt, den Destruktor explizit aufzurufen, oder? Aber gilt die Lebensdauer des Objekts danach als beendet? Das heißt, ist der Aufruf eines anderen Mitglieds nach dem expliziten Aufruf des Destruktors erlaubt (definiert)?

Zusammenfassend, welche Teile des obigen Codes (wenn überhaupt) zu undefiniertem Verhalten (technisch gesprochen) führen?

+0

Aber der Konstruktor wird nur 3 mal aufgerufen, also wie ist der Destruktor 4 mal logisch? Es würde bombardieren, sobald die Klasse (nicht-triviale) Datenmitglieder bekommt. – visitor

+0

- es heißt "Verweigerung" – slashmais

Antwort

2

p-> ~ SomeClass(); // Zeile 5

p-> CommitSuicide(); // Zeile 6

Zeile (6) ruft definitiv Undefined Behavior auf.

Das heißt, ist der Aufruf eines anderen Mitglieds nach dem expliziten Aufruf des Destruktors erlaubt (definiert)?

Nein! Deine Annahme ist richtig.

+0

Zeile 6 "sollte" einen Speicherzugriffsfehler geben (segfault auf linux), da der zuvor von der Instanz von SomeClass belegte Adressraum von p "sollte" gewesen sein soll vom Betriebssystem ordnungsgemäß freigegeben. Oder führt der Destruktor einen späten Aufruf zum Löschen aus? – slashmais

+0

@slashmais: Nein, es gibt keine solche Garantie, und sehr wenige Implementierungen funktionieren so. Die meisten Implementierungen haben eine Vorstellung von "freiem Speicherplatz", was Speicher ist, der vom Betriebssystem dem Programm zugewiesen wird, jedoch keine Objekte enthält. Von gelöschten Objekten zurückgewonnener Speicher wird in diesen "freien Raum" zurückgeführt, um von zukünftigen Objekten verwendet zu werden. – MSalters

+0

Ja, ich dachte, es wäre so etwas. Erklärt Zeile 6 folgt dann, weil der Raum noch nicht recycelt wurde. – slashmais

6

Die delete this; ist in Ordnung. Die letzte p->CommitSuicide(); gibt undefiniertes Verhalten, weil Sie das Objekt bereits in "Zeile 5" zerstört haben.

0

"delete this" ist in Ordnung, solange Sie nicht versuchen, einen Code dieses Objekts nach dem Löschen (nicht einmal der Destruktor) aufzurufen. Daher sollte ein selbstlöschendes Objekt nur auf dem Heap platziert werden und einen privaten Destruktor haben, um vor der Erstellung auf dem Stapel zu schützen.

Ich weiß nicht, ob ein direkter Aufruf an den Destruktor zu undefiniertem Verhalten führt, aber ein benutzerdefinierter delete-Operator würde nicht ausgeführt werden.

Verwandte Themen