Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does `std::exit` not trigger destructors as expected?

Tags:

#include <cstdlib> #include <thread> #include <chrono> #include <iostream>  using namespace std; using namespace std::literals;  struct A {     int n_ = 0;     A(int n) : n_(n) { cout << "A:" << n_ << endl; }     ~A() { cout << "~A:" << n_ << endl; } };  A a1(1);  int main() {     std::thread([]()     {         static A a2(2);         thread_local A a3(3);         std::this_thread::sleep_for(24h);     }).detach();      static A a4(4);     thread_local A a5(5);      std::this_thread::sleep_for(1s);     std::exit(0); } 

My compiler is clang 5.0 with -std=c++1z.

The output is as follows:

A:1 A:2 A:4 A:5 A:3 ~A:5 ~A:2 ~A:4 ~A:1 

Note that there is no ~A:3, which means the object A a3 was not destructed.

However, according to cppref:

std::exit causes normal program termination to occur. Several cleanup steps are performed:

The destructors of objects with thread local storage duration ... are guaranteed to be called.

like image 312
xmllmx Avatar asked Mar 28 '17 14:03

xmllmx


People also ask

Does STD exit call destructors?

std::exit causes normal program termination to occur. Several cleanup steps are performed: The destructors of objects with thread local storage duration ... are guaranteed to be called.

Are destructors called on exit in C++?

No, most destructors are not run on exit() . Essentially, when exit is called static objects are destroyed, atexit handlers are executed, open C streams are flushed and closed, and files created by tmpfile are removed.

What does std :: exit do?

std::exit. Causes normal program termination to occur.


1 Answers

Objects with thread storage duration are guaranteed to be destroyed only for the thread which calls exit. Quoting C++14 (N4140), [support.start.term] 18.5/8 (emphasis mine):

[[noreturn]] void exit(int status) 

The function exit() has additional behavior in this International Standard:

  • First, objects with thread storage duration and associated with the current thread are destroyed. Next, objects with static storage duration are destroyed and functions registered by calling atexit are called. See 3.6.3 for the order of destructions and calls. (Automatic objects are not destroyed as a result of calling exit().) If control leaves a registered function called by exit because the function does not provide a handler for a thrown exception, std::terminate() shall be called (15.5.1).
  • 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.
  • 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.

The standard therefore does not guarantee destruction of objects with thread storage duration associated with other threads than the one calling exit.

like image 83
Angew is no longer proud of SO Avatar answered Nov 10 '22 09:11

Angew is no longer proud of SO