6 Basics [basic]

6.10 Program execution [basic.exec]

6.10.3 Start and termination [basic.start]

6.10.3.4 Termination [basic.start.term]

Constructed complete objects ([dcl.init]) with static storage duration are destroyed and functions registered with std​::​atexit are called as part of a call to std​::​exit ([support.start.term]).
The call to std​::​exit is sequenced before the destructions and the registered functions.
[Note 1: 
Returning from main invokes std​::​exit ([basic.start.main]).
— end note]
Constructed complete objects with thread storage duration within a given thread are destroyed as a result of returning from the initial function of that thread and as a result of that thread calling std​::​exit.
The destruction of those constructed objects is sequenced before releasing the storage for any object with thread storage duration within that thread ([basic.stc.thread]).
The destruction of those constructed objects strongly happens before destroying any object with static storage duration.
The destruction of a complete object with thread storage duration within a given thread and having constant destruction ([expr.const]) is sequenced after the destruction of any other complete object with thread storage duration within the thread.
The destruction of a complete object with static storage duration and having constant destruction is sequenced after the destruction of any other complete object with static storage duration and after any call to a function passed to std​::​atexit.
The sequencing rules in the remainder of this subclause apply only to complete objects not having constant destruction.
If the deemed construction ([dcl.init.general]) of a complete object with static storage duration strongly happens before that of another, the completion of the destruction of the second is sequenced before the initiation of the destruction of the first.
If the deemed construction of a complete object with thread storage duration is sequenced before that of another, the completion of the destruction of the second is sequenced before the initiation of the destruction of the first.
If an object is initialized statically, the object is destroyed in the same order as if the object was dynamically initialized.
If the destruction of an object with static or thread storage duration exits via an exception, the function std​::​terminate is called ([except.terminate]).
[Example 1: 
In the following program, the elements of a are destroyed, followed by dt, and finally by the two Btemp objects: struct DTemp { ~DTemp(); }; struct Temp { ~Temp() { static DTemp dt; } }; struct BTemp { ~BTemp(); }; struct A { const BTemp &tb; ~A(); }; A a[] = { (Temp(), BTemp()), BTemp() }; int main() {}
If the array a were an object with automatic storage duration, the Btemp temporaries would be destroyed as each element of the array is destroyed ([class.temporary]).
— end example]
If a function contains a block variable of static or thread storage duration that has been destroyed and the function is called during the destruction of an object with static or thread storage duration, the program has undefined behavior if the flow of control passes through the definition of the previously destroyed block variable.
[Note 2: 
Likewise, the behavior is undefined if the block variable is used indirectly (e.g., through a pointer) after its destruction.
— end note]
If the deemed construction of a complete object with static storage duration strongly happens before a call to std​::​atexit (see <cstdlib>, [support.start.term]), the call to the function passed to std​::​atexit is sequenced before the initiation of the destruction of the object.
If a call to std​::​atexit strongly happens before the deemed construction of a complete object with static storage duration, the completion of the destruction of the object is sequenced before the call to the function passed to std​::​atexit.
If a call to std​::​atexit strongly happens before another call to std​::​atexit, the call to the function passed to the second std​::​atexit call is sequenced before the call to the function passed to the first std​::​atexit call.
If there is a use of a standard library object or function not permitted within signal handlers ([support.runtime]) that does not happen before ([intro.multithread]) completion of destruction of objects with static storage duration and execution of std​::​atexit registered functions ([support.start.term]), the program has undefined behavior.
[Note 3: 
If there is a use of an object with static storage duration that does not happen before the object's destruction, the program has undefined behavior.
Terminating every thread before a call to std​::​exit or the exit from main is sufficient, but not necessary, to satisfy these requirements.
These requirements permit thread managers as static-storage-duration objects.
— end note]
Calling the function std​::​abort() declared in <cstdlib> terminates the program without executing any destructors and without calling the functions passed to std​::​atexit() or std​::​at_quick_exit().