2009-09-01 6 views
2

Wie stellt C++ sicher, dass Destruktoren für stack-assigned-Objekte aufgerufen werden? Was geschieht mit der Destruktor-Funktion (oder einen Zeiger darauf), wenn I dynamischen Speicher zuweisen, wie folgt:Mit welchem ​​Mechanismus werden Destruktoren für stack-assigned Objekte aufgerufen?

class MyClass { 
public: 

    ~MyClass() 
    { 
    std::cout<<"Destructor called."<<std::endl; 
    } 

    MyClass() 
    { 
    std::cout<<"Constructor called."<<std::endl; 
    } 

}; 

.................................................................... 

//Limit scope for example 
{ 
    MyClass instance; 
} 

Der Konstruktor und destructor beide genannt. Was ist denn hier los?

+0

Beispiel ist der Name des Objekts. instance() ist einfach ein Aufruf an das no-Argument ctor der Klasse.Die Parens sind in diesem Fall unnötig, aber es ist sicherlich kein Aufruf einer Methode namens instance(). – dicroce

+5

Ich sehe keine dynamische Speicherzuweisung. –

Antwort

7

Der Compiler fügt einen Aufruf an den Destruktor für das Objekt an einer geeigneten Position ein.

1

Der Konstruktor wird aufgerufen, weil Sie ein Objekt erstellen. Der Destruktor wird aufgerufen, weil Sie dieses Objekt bereinigen. Denken Sie daran, dass in C++ Objekte, die auf dem Stapel deklariert sind, automatisch bereinigt werden, wenn der zugehörige Bereich nicht mehr vorhanden ist.

3

Der Konstruktor wird aufgerufen, sobald die Variable erstellt wurde. Was den Destruktor betrifft, gibt der Compiler am Ende des Bereichs Code aus, um den Destruktor aufzurufen. Versuchen Sie, ein "goto" oder switch/case-Konstrukt zu verwenden, um den Gültigkeitsbereich vorzeitig zu verlassen, und beobachten Sie, wie der Compiler sich beschwert.

+1

"Der Konstruktor wird aufgerufen, sobald die Variable erstellt wurde." Nun, die Objekterstellung geschieht, wenn der Konstruktor aufgerufen wird, also ist das kein Wunder. Der Speicher für die Variable OTOH könnte früher bereitgestellt werden. – sbi

+1

Sie können den Bereich mit goto verlassen, soweit ich weiß, und der Compiler wird immer noch wissen, dass das Objekt den Gültigkeitsbereich verlässt. Was Sie nicht tun dürfen, ist mit goto/switch über Objektdeklarationen (Construction) zu treten. – UncleBens

+0

@UncleBens: Machen Sie diese "Objektdefinitionen", aber sonst haben Sie Recht. (Ich las zu schnell und hatte diesen Fehler in Managus Antwort nicht gesehen.) – sbi

3

Ja, sowohl der Konstruktor als auch der Destruktor werden aufgerufen. Und noch wichtiger:

{ 
MyClass instance; 
throw "exception"; 
} 

In diesem Beispiel wird auch der Destruktor aufgerufen. Deshalb ziehe ich es vor, meine Objekte immer auf dem Stack zu platzieren (oder zumindest die dynamischen Zuordnungen mit einem Stack-zugewiesenen Guardian zu umhüllen).

4

würden Sie nicht fragen, warum dieser

{ 
    int i; 
} 

und i automatisch zerstört schafft, würden Sie? C++ bietet eine Menge Möglichkeiten, um Typen zu erstellen, die sich genau wie integrierte Typen verhalten. Und genau wie mit eingebauten Typen, in C++ (anders als etwa in Java oder C#), das

{ 
    MyClass instance; 
} 

nicht nur eine Referenz definieren, die null oder einem tatsächlichen Objekt gebunden werden könnten. Es erstellt ein tatsächliches Objekt.

Die Erstellung der Objekte erfolgt in zwei Schritten: Zuerst (nach Eingabe des Bereichs) wird der Rohspeicher bereitgestellt. Dann (wenn die Objektdefinition angetroffen wird) wird der Konstruktor aufgerufen. Für eingebaute Typen wird kein Konstruktor aufgerufen. Wenn Sie eine integrierte Variable nicht initialisieren, hat sie einen zufälligen Wert. (Tatsächlich ist es das, was das Bitmuster in dem in Schritt 1 bereitgestellten Speicher war.) Das Löschen von Objekten erfolgt ebenfalls in zwei Schritten: Zuerst wird der Destruktor aufgerufen (wiederum nicht für eingebaute), dann wird zu dem Speicher zurückgekehrt das Laufzeitsystem.

(Beachten Sie, dass die Bereitstellung und in der Regel Speicher für Stack-Variablen zu löschen, wie billig ist als incementing/Erniedrigen eines Registers.)

0

Nun, es hat den Destruktor nicht nur nach dem Konstruktor aufrufen.
Es ruft es auf, wenn es das Programm beenden soll.

int main() { 
    MyClass obj; 
    cout<<"testing....1"<<endl; 
    cout<<"testing....2"<<endl; 
    return 0; 
} 

am:

Constructor called. 
testing....1 
testing....2 
Destructor called. 
+1

Es ruft den Destruktor nicht auf, wenn das Programm beendet wird. Der Destruktor wird aufgerufen, wenn das Stapelobjekt den Gültigkeitsbereich verlässt. Weil du das hauptsächlich machst, fallen diese beiden zufällig zusammen. –