2008-10-21 17 views
43

Ich erwartete A::~A() in diesem Programm aufgerufen werden, aber es ist nicht:Warum Destruktor bei Ausnahme nicht aufgerufen wird?

#include <iostream> 

struct A { 
    ~A() { std::cout << "~A()" << std::endl; } 
}; 

void f() { 
    A a; 
    throw "spam"; 
} 

int main() { f(); } 

Allerdings, wenn ich letzte Zeile zu

int main() try { f(); } catch (...) { throw; } 

dann A::~A()ist genannt ändern.

Ich kompiliere mit "Microsoft (R) 32-Bit-C/C++ Optimierungscompiler Version 14.00.50727.762 für 80 x 86" von Visual Studio 2005. Befehlszeile ist cl /EHa my.cpp.

Ist Compiler richtig wie gewohnt? Was sagt der Standard dazu?

+0

Nur zur Information, reproduziert ich das gleiche Problem mit dem gleichen Code in Visual C++ 2003. +1 für die Frage. – paercebal

Antwort

61

Der Destruktor wird nicht aufgerufen, da terminate() für die unbehandelte Ausnahme aufgerufen wird, bevor der Stapel abgewickelt wird.

Die spezifischen Details von was die C++ - Spezifikation sagt, ist außerhalb meines Wissens, aber ein Debug-Trace mit Gdb und G ++ scheint dies zu bestätigen.

Nach dem draft standard Abschnitt 15.3 Punkt 9:

 
9 If no matching handler is found in a program, the function terminate() 
    (_except.terminate_) is called. Whether or not the stack is unwound 
    before calling terminate() is implementation-defined. 
2

Im zweiten Beispiel wird das dtor aufgerufen, wenn es den try {} -Block verlässt.

Im ersten Beispiel wird der Befehl dtor aufgerufen, wenn das Programm nach dem Verlassen der Funktion main() beendet wird - zu diesem Zeitpunkt könnte cout bereits zerstört worden sein.

+0

Nein, das ist falsch. Der Destruktor wird garantiert aufgerufen, bevor das Programm 'main' verlässt. Der 'cout'-Destruktor wird garantiert * danach * aufgerufen. –

+0

... Korrektur: der Destruktor von 'a' muss aufgerufen werden, bevor' f' übrig bleibt! –

+0

Auch das Programm verlässt im ersten Beispiel nie main. Es wird über eine "unerwartete Ausnahme" abgebrochen. – ejgottl

2

Ich nahm auch an, dass der Compiler nicht den Code relativ zu "a" erzeugt, da er nicht referenziert ist, aber trotzdem ist es nicht das richtige Verhalten, da der Destruktor etwas ausführt.

Also, ich versuchte in VS2008/vc9 (+ SP1), Debug und Release und ~ A wird nach der Ausnahme aufgerufen, aus f() - das ist das richtige Verhalten, wenn ich Recht habe.

Jetzt habe ich gerade mit VS2005/vc8 (+ SP1) versucht und es ist das gleiche Verhalten.

Ich habe Haltepunkte verwendet, um sicher zu sein. Ich habe gerade mit der Konsole gecheckt und ich habe auch die "~ A" Nachricht. Vielleicht hast du es woanders falsch gemacht?

+0

Ich erstellte Textdatei mit dem ersten Beispiel (ohne Versuch), öffnete "Visual Studio 2005 Eingabeaufforderung" und kompilierte Datei mit 'cl/EHa my.cpp'. Ergebnis ausführen: Diese Anwendung hat die Runtime aufgefordert, sie auf ungewöhnliche Weise zu beenden. Wenden Sie sich für weitere Informationen bitte an das Support-Team der Anwendung. – Constantin

+0

Ich bin nicht vertraut mit den Kompilierparametern in der Kommandozeile, aber ich denke, dass es ähnlich dem Freigabemodus ist. Wenn es keinen try/catch gibt, kommt der Code nicht weiter als der throw-Befehl (das passiert, wenn ich es versuche) und die Anwendung wird nur "abstürzen" (das ist das gewünschte Verhalten) – Klaim

+0

Nachdem ich Assembly-Listings betrachtet habe, glaube ich, dass Optimierungen standardmäßig deaktiviert sind. Es ist also näher an Debug. Übrigens, siehe Kommentar von Paercebal, er/sie hat es geschafft mit VS2003 zu reproduzieren. – Constantin

1

Sorry, ich habe mich nicht über eine Kopie des Standards.
Ich würde auf jeden Fall wie eine endgültige Antwort auf diese, so jemand mit Kopie des Standard-Kapitel und Vers teilen wollen, was geschieht:

  • Die Ausnahme:

    Von meinem Verständnis ist nur iff genannt terminate Der Handlingsmechanismus kann keinen Handler für eine ausgelöste Ausnahme finden.
    Die folgenden Fälle sind genauer:

    • Während des Abwickelns des Stacks entkommt eine Exception einem Destruktor.
    • Bei einem ausgelösten Ausdruck wird der Konstruktor durch eine Ausnahme entkoppelt.
    • Eine Ausnahme entkommt dem Konstruktor/Destruktor einer nicht lokalen statischen (dh globalen)
    • Eine Ausnahme entkommt eine Funktion, die mit atexit() registriert ist.
    • Eine Ausnahme entkommt Haupt()
  • Der Versuch, eine Ausnahme erneut auslösen, wenn keine Ausnahme propagieren derzeit.
  • eine unerwartete Ausnahme entkommt eine Funktion mit Ausnahme Spezifizierer (über unerwartete)
13

C++ Sprachspezifikation Zustände: Der Prozess der Destruktoren zum automatischen Objekten aufgebaut auf dem Weg von einem try-Block zu einem Wurf-expression Aufruf heißt "stack unwinding". Ihr ursprünglicher Code enthält keinen try-Block, deshalb kommt es nicht zum Abstapeln des Stapels.

2

Diese Frage ist einfach zu google, also teile ich meine Situation hier.

Stellen Sie sicher, yor exeption nicht extern "C" Grenze nicht überschreitet oder verwenden MSVC Option/EHs (Enable C++ exeptions = Ja mit Extern C-Funktionen (/ EHS))

Verwandte Themen