std::exit
| Definiert im Header <cstdlib>
|
||
void exit( int exit_code );
|
(bis C++11) | |
[[noreturn]] void exit( int exit_code );
|
(seit C++11) | |
Verursacht die normale Programmbeendigung.
Es werden mehrere Aufräumschritte durchgeführt:
|
1) Objekte mit statischer Speicherdauer werden zerstört und Funktionen, die durch Aufruf von std::atexit registriert wurden, werden aufgerufen:
a) Nicht-lokale Objekte mit statischer Speicherdauer werden in umgekehrter Reihenfolge des Abschlusses ihres Konstruktors zerstört.
b) Mit std::atexit registrierte Funktionen werden in umgekehrter Reihenfolge ihrer Registrierung aufgerufen, außer dass eine Funktion nach allen zuvor registrierten Funktionen aufgerufen wird, die zum Zeitpunkt ihrer Registrierung bereits aufgerufen worden waren.
c) Für jede Funktion
f, die mit std::atexit registriert wurde, und jedes nicht-lokale Objekt obj mit statischer Speicherdauer:
d) Für jedes lokale Objekt obj mit statischer Speicherdauer wird obj so zerstört, als ob beim Abschluss des Konstruktors von obj eine Funktion, die den Destruktor von aufruft, mit std::atexitobj registriert worden wäre.
|
(bis C++11) |
|
1) Die Destruktoren von Objekten mit Thread-lokaler Speicherdauer, die mit dem aktuellen Thread verbunden sind, die Destruktoren von Objekten mit statischer Speicherdauer und die mit std::atexit registrierten Funktionen werden gleichzeitig ausgeführt, wobei die folgenden Garantien eingehalten werden:
a) Der letzte Destruktor für Thread-lokale Objekte ist sequenziert-vor dem ersten Destruktor für ein statisches Objekt.
b) Wenn der Abschluss des Konstruktors oder der dynamischen Initialisierung für ein Thread-lokales oder statisches Objekt A sequenziert-vor Thread-lokalem oder statischem Objekt B war, dann ist der Abschluss der Zerstörung von B sequenziert-vor dem Beginn der Zerstörung von A.
c) Wenn der Abschluss der Initialisierung eines statischen Objekts A sequenziert-vor dem Aufruf von std::atexit für eine Funktion F war, dann ist der Aufruf von F während der Beendigung sequenziert-vor dem Beginn der Zerstörung von A.
d) Wenn der Aufruf von std::atexit für eine Funktion F sequenziert-vor dem Abschluss der Initialisierung eines statischen Objekts A war, dann ist der Beginn der Zerstörung von A sequenziert-vor dem Aufruf von F während der Beendigung.
e) Wenn ein Aufruf von std::atexit für eine Funktion F1 sequenziert-vor dem Aufruf von std::atexit für eine Funktion F2 war, dann ist der Aufruf von F2 während der Beendigung sequenziert-vor dem Aufruf von F1.
|
(seit C++11) |
- Im obigen Text:
- Wenn eine mit
atexitregistrierte Funktion oder ein Destruktor eines statischen/Thread-lokalen Objekts eine Ausnahme auslöst, wird std::terminate aufgerufen. - Wenn der Compiler die dynamische Initialisierung eines Objekts in die statische Initialisierungsphase der nicht-lokalen Initialisierung verlagert hat, folgt die Sequenzierung der Zerstörung ihrer hypothetischen dynamischen Initialisierung.
- Wenn ein funktionslokales (blockbezogenes) statisches Objekt zerstört wurde und diese Funktion dann vom Destruktor eines anderen statischen Objekts aufgerufen wird und der Kontrollfluss durch die Definition dieses Objekts verläuft (oder wenn es indirekt über Zeiger oder Referenz verwendet wird), ist das Verhalten undefiniert.
- Wenn ein funktionslokales (blockbezogenes) statisches Objekt während der Konstruktion eines Unterobjekts einer Klasse oder eines Arrays initialisiert wurde, wird es erst zerstört, nachdem alle Unterobjekte dieser Klasse oder alle Elemente dieses Arrays zerstört wurden.
- Wenn eine mit
exit_code gleich 0 oder EXIT_SUCCESS ist, wird ein implementationsdefinierter Status zurückgegeben, der eine erfolgreiche Beendigung anzeigt. Wenn exit_code gleich EXIT_FAILURE ist, wird ein implementationsdefinierter Status zurückgegeben, der eine erfolglose Beendigung anzeigt. In anderen Fällen wird ein implementationsdefinierter Statuswert zurückgegeben.Der Stack wird nicht abgewickelt: Destruktoren von Variablen mit automatischer Speicherdauer werden nicht aufgerufen.
Beziehung zur main-Funktion
Die Rückkehr von der
main-Funktion
, entweder durch eine
return
-Anweisung oder durch das Erreichen des Funktionsendes, führt die normale Funktionsbeendigung durch (ruft die Destruktoren der Variablen mit automatischer
Speicherdauer
auf) und führt dann
std::exit
aus, wobei das Argument der return-Anweisung (oder
0
bei impliziter Rückgabe) als
exit_code
übergeben wird.
Parameter
| exit_code | - | Exit-Status des Programms |
Beispiel
#include <cstdlib> #include <iostream> struct Static { ~Static() { std::cout << "Static destructor\n"; } }; struct Local { ~Local() { std::cout << "Local destructor\n"; } }; Static static_variable; // Destruktor dieses Objekts *wird* aufgerufen void atexit_handler() { std::cout << "atexit handler\n"; } int main() { Local local_variable; // Destruktor dieses Objekts wird *nicht* aufgerufen const int result = std::atexit(atexit_handler); // Handler wird aufgerufen if (result != 0) { std::cerr << "atexit registration failed\n"; return EXIT_FAILURE; } std::cout << "test\n"; std::exit(EXIT_FAILURE); std::cout << "this line will *not* be executed\n"; }
Ausgabe:
test atexit handler Static destructor
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| LWG 3 | C++98 |
während des Cleanups war das Verhalten unklar, wenn (1) eine Funktion mit
std::atexit registriert wird oder (2) ein statisches lokales Objekt initialisiert wird |
klargestellt |
Siehe auch
|
verursacht abnormale Programmbeendigung (ohne Bereinigung)
(Funktion) |
|
|
registriert eine Funktion, die beim Aufruf von
std::exit()
aufgerufen wird
(Funktion) |
|
|
(C++11)
|
verursacht schnelle Programmbeendigung ohne vollständige Bereinigung
(Funktion) |
|
(C++11)
|
registriert eine Funktion, die beim Aufruf von
std::quick_exit
aufgerufen wird
(Funktion) |
|
C-Dokumentation
für
exit
|
|