2017-02-22 1 views
0

Aus Neugier habe ich versucht, etwas wie das folgende Beispiel zu machen, um zu sehen, ob der Compiler mich warnt oder nicht, anstatt eine Endlosschleife aufzurufen, die in einem Stapelüberlauf endet. Ich dachte, vielleicht gibt es ein anderes Verhalten als nur normale Funktionen oder Methoden aufzurufen. Aber das ist nicht der Fall. Gibt es eine spezielle Erklärung dafür oder wird es nur als normale Funktionsaufrufe behandelt, da ich den Basisklassen-Destruktor explizit mit dem Operator this aufruft?Wie behandelt der Compiler im abgeleiteten Destruktor Basisklassen-Destruktoraufrufe?

Beispiel:

class A { 
    virtual ~A(); 
}; 

class B : A { 
    virtual ~B() { this->~A(); } 
}; 
+2

'virtual void ~ A();' - Dies sollte nicht kompilieren, Destruktoren geben nichts zurück, und normale Methodenname kann nicht enthalten Tilda. – yeputons

+0

@yeputons Recht, sry, war ein Tippfehler –

+4

Es wird undefiniertes Verhalten durch zweimaliges Aufrufen von '~ A()' (da gibt es einen impliziten Aufruf einmal '~ B()' s Körper beendet) –

Antwort

2

@ M. M Kommentar traf es. Sie rufen den Destruktor zweimal auf. Dies ist ein undefiniertes Verhalten und alles kann passieren, einschließlich des Verhaltens, das Sie beobachten.

(In Wirklichkeit höchstwahrscheinlich eine dieser destructor Anrufe ändert die vptr des Objekts, was bedeutet, dass nachfolgende destructor nicht mehr auf die am meisten abgeleitete Objekt gehen Anrufe. Aber das ist nur eine Vermutung.)

Die richtige Sache Zu tun ist, den Destruktor nicht manuell aufzurufen.

+1

C++ 14 [class.dtor]/15 ist die Klausel, die speziell besagt, dass ein zweiter Destruktoraufruf UB ist, für Klassen mit nicht-trivialem Destruktor (was das ist, da "virtuell" es nicht-trivial macht) –

0

Der Aufruf des virtuellen Destruktors der abgeleiteten Klasse bewirkt den Aufruf des Basisklassen-Destruktors. Aber nicht umgekehrt.

1

Virtuelle Destruktoren in einer abgeleiteten Klasse rufen immer zuerst die Destruktoren der Elternklasse auf, und zwar in einer rekursiven Reihenfolge, so dass der meist "ursprüngliche" Basisklasse-Destruktor aufgerufen wird, und dann der zweitmeisten "Vorfahren". usw. Stellen Sie sich vor, dass Child von Parent erbt, das von GrandParent erbt. Der Destruktor der Child-Klasse ruft tatsächlich den Destruktor von GrandParent, dann den Destruktor von Parent und dann den Destruktor von Child auf.

In der Tat rufen Ihre abgeleiteten Klassenkonstruktoren auch ihre Elternklassenkonstruktoren in derselben rekursiven Reihenfolge auf. Sie müssen sich abgeleitete Klassen wie einen "Schichtkuchen" vorstellen: Jede Instanz der Vererbung fügt Ihrem Objekt eine Ebene hinzu. Die Child-Klasse hat also drei Ebenen {GrandParent, Parent, Child}, die Konstruktion/Zerstörung jeder Ebene wird von der entsprechenden Klasse gehandhabt.

Was Sie versuchen, wird versuchen, den Eltern-Destruktor zweimal aufzurufen, was eine schlechte Idee ist. Im Allgemeinen müssen Sie Destruktoren nicht explizit aufrufen, es sei denn, Sie haben den Operator new überladen. Siehe diese Antwort für weitere Details: Is calling destructor manually always a sign of bad design?

Verwandte Themen