2016-05-04 16 views
0

Ich habe diese Baumstruktur:C++ destructor für Baumstruktur

public: 
    node(string& const n); 
    virtual ~node(); 
    string get_name() const; 
    void set_name(string& new_name); 
    int get_nr_children() const; 
    node get_child(int i) const; 
    void add_child(node child); 
private: 
    string& name; 
    vector<node> children; 
}; 

und meine main.cpp sieht wie folgt aus:

int main() { 
    string s = "root"; 
    node r(s); 
    string s2 = "left child"; 
    node ls(s2); 
    string s3 = "right child"; 
    node rs(s3); 

    r.add_child(ls); 
    r.add_child(rs); 

    r.~node(); 
} 

(Ich weiß, dass ~node() auf alle Objekte in der ohnehin läuft Ende der main funciton, aber ich möchte sicherstellen, dass es auf der Wurzel r zuerst ausgeführt wird)

Alle Methoden funktionieren soweit, bis auf th e Destruktor. Dies ist mein erster Destruktor, und ich kam zu dem folgenden rekursiven Versuch, weiß aber nicht, warum es nicht funktioniert.

node::~node() { 
    cout << "Enter ~node of " << this->get_name() << endl; 
    while (this->get_nr_children() != 0) { 
     this->get_child(0).~node(); 
     this->children.pop_back(); 
    } 
    delete this; 
    cout << "Leave ~node of " << this->get_name() << endl; 
} 

Das Ergebnis ist eine endlose Ausgabe von „Enter ~ Knoten von links Kind“

+2

_delete dies; '_ Huh ???? Das ist eklatant falsch! –

+3

Rufen Sie Destruktoren nicht direkt auf. Stattdessen benutze 'delete' (besser noch: benutze Container oder Smart Pointer). – crashmstr

+1

Ohne zu sehen, was "add_child" alles bietet, was wir anbieten können, ist Spekulation. Mach ein [mcve]. Sie greifen auch direkt nach dem Löschen auf diese Datei zu. – nwp

Antwort

1

Dies ist ungültig und die Erträge nicht definiertes Verhalten, wenn es kompiliert:

vector<node> children; 

An der Stelle dieser Daten Mitgliedserklärung die Klasse node ist unvollständig; seine Größe ist noch nicht bekannt.

Sie können einen unvollständigen Typ nicht als Elementtyp für einen Standardbibliothekscontainer verwenden (Sie können jedoch Zeiger verwenden).


In der destructor Implementierung auch

delete this; 

nicht definiertes Verhalten, eine unendliche Rekursion die destructor Aufruf, die (in diesem delete Ausdruck) nennt sich, und so weiter führt.


Die Datenelementdeklaration

string& name; 

hat auch einen starken, unangenehmen Geruch darüber, aber da Sie nicht die Konstruktor-Implementierungen zeigen kann ich nicht kategorisch aus 100% sagen, dass es falsch ist.

Mit dem Rest des Codes ist jedoch die Wahrscheinlichkeit, dass dies richtig ist, infinitesimal. Verwenden Sie einfach

string name_; 
+0

Der erste ist in C++ 1z erlaubt. –

+0

@ T. C .; Sie meinen, dass es höchstwahrscheinlich in C++ 17 unterstützt wird. Danke, ich wusste es nicht. Hast du eine Referenz? –

+0

http://eel.is/c++draft/vector#vector.overview-3 –

3

„(Ich weiß, dass ~ Knoten() auf alle Objekte ohnehin am Ende des Haupt funciton ausgeführt wird, aber ich möchte sicherstellen, dass es auf der Wurzel r zuerst ausgeführt wird)“

Dieses Zitat ist genug zu sagen, dass alles in dieser Frage nur auf Missverständnisse basiert.

Es macht nicht einmal Sinn zu versuchen, zu korrigieren: eine vollständige Neuschreibung ist notwendig.

Stattdessen lesen Sie mehr über Destrcuctors, deren Aufruf und was sie sind.

Der explizite Aufruf unterdrückt den impliziten Aufruf nicht. Und doppelte Zerstörung ist undefiniertes Verhalten.

Auch delete this ist etwas sehr knifflig erfordern Sie müssen sehr sicher sein, was es bedeutet.

Und Zugriff auf Klassenmethoden (this->...) oder Daten nach dem Löschen ... sucht nur nach Problemen.

1

Normalerweise verwendet eine Struktur Knoten, die im freien Speicher zugeordnet sind. Das bedeutet Trafficking von Zeigern auf Knoten und Löschen von Knoten, die nicht mehr verwendet werden. Der Code in der Frage folgt nicht diesem Modell: Er weist den Stammknoten im Stapel zu und speichert Knotenobjekte statt Zeiger in jedem Knoten. Mit diesem Code funktionieren alle vom Compiler erzeugten Destruktoren problemlos. Es sind keine benutzerdefinierten Destruktoren erforderlich.