Funktion "exit" und Aufräumen des Stacks
-
Wie kann ich es beim Aufrufen von
exithinbekommen, dass der Stack vorher noch aufgeräumt wird?Beispiel: Ich habe folgenden Quellcode:
#include <iostream> #include <cstdlib> using namespace std; class Test { public: ~Test() { cout << "Destruktor\n"; } }; void Ende() { cout << "Ende-Funktion\n"; } int main() { atexit(Ende); Test t; // exit(0); cout << "Ende main\n"; }Dieser gibt mir folgendes aus:
Ende main Destruktor Ende-FunktionSo weit, so gut. Wenn ich nun aber den auskommentierten Aufruf in Zeile 27 wieder reinnehme, gibt es nur noch folgendes als Ausgabe:
Ende-FunktionIch hätte jetzt aber erwartet, dass er den Destruktor der Klasse
Testnoch aufruft und somit den Stack bereinigt, statt die Variablen jetzt unaufgeräumt stehen zu lassen. Würde ichexit(0);durchreturn 0;ersetzen, würde ja dort auchDestruktor Ende-Funktionstehen.
Deshalb würde ich gerne wissen:
1. Wieso wird die lokale Variable nicht korrekt zerstört? Im Gegensatz zurabort-Funktion heißt es überexitja schließlich:www.cplusplus.com/reference/clibrary/cstdlib/exit schrieb:
Terminates the process normally, performing the regular cleanup for terminating processes.
2. Wie kann ich sicherstellen, dass meine auf dem Stack erstellten Variablen im Falle eines Aufrufs von
exitsauber gelöscht werden?
-
Die Funktion exit stammt noch aus C und dort gibt es bekanntlich keine Klassen mit Konstruktoren/Destruktoren. Folglich ist die Funktion in C++ nicht zu empfehlen. Für Fehlerbehandlung, etc. gibt es in C++ Exceptions.
-
Steht so im Standard. In einer Fußnote steht sogar eine mögliche Lösung für dein Problem:
ISO/IEC 14882:2003 18.3 (8) schrieb:
The function exit() has additional behavior in this International Standard:
— First, objects with static storage duration are destroyed and functions registered by calling atexit are called. Non-local objects with static storage duration are destroyed in the reverse order of the completion of their constructor. (Automatic objects are not destroyed as a result of calling exit().)207) Functions registered with atexit are called in the reverse order of their registration, except that a function is called after any previously registered functions that had already been called at the time it was registered.208) A function registered with atexit before a non-local object obj1 of static storage duration is initialized will not be called until obj1’s destruction has completed. A function registered with atexit after a non-local object obj2 of static storage duration is initialized will be called before obj2’s destruction starts. A local static object obj3 is destroyed at the same time it would be if a function calling the obj3 destructor were registered with atexit at the completion of the obj3 constructor.
— Next, all open C streams (as mediated by the function signatures declared in <cstdio>) with unwritten buffered data are flushed, all open C streams are closed, and all files created by calling tmpfile() are removed.209)
— Finally, control is returned to the host environment. If status is zero or EXIT_SUCCESS, an implementation-defined form of the status successful termination is returned. If status is EXIT_FAILURE, an implementation-defined form of the status unsuccessful termination is returned. Otherwise the status returned is implementation-defined.210)207) Objects with automatic storage duration are all destroyed in a program whose function main() contains no automatic objects and executes the call to exit(). Control can be transferred directly to such a main() by throwing an exception that is caught in main().
208) A function is called for every time it is registered.
209) Any C streams associated with cin, cout, etc (27.3) are flushed and closed when static objects are destroyed in the previous phase. The function tmpfile() is declared in <cstdio>.
210) The macros EXIT_FAILURE and EXIT_SUCCESS are defined in <cstdlib>.
-
#include <iostream> #include <cstdlib> using namespace std; class ExitException { private: size_t code; public: ExitException(size_t code_) : code(code_) { } void Exit() const { exit(code); } }; class Test { public: ~Test() { cout << "Destruktor\n"; } }; void Ende() { cout << "Ende-Funktion\n"; } int main() { try { atexit(Ende); Test t; throw ExitException(0); cout << "Ende main\n"; } catch (ExitException& e) { e.Exit(); } }