Are Destructors Run When Calling Exit()

Are destructors run when calling exit()?

No, most destructors are not run on exit().

C++98 §18.3/8 discusses this.

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. Local automatic objects are not destroyed. I.e., no stack unwinding.

Calling abort lets even less happen: no cleanup whatsoever.

How to properly call destructors when exiting within a thread?

It is the thread that calls exit that does all of the cleanup.

Several cleanup steps are performed:

  1. The destructors of objects with thread local storage duration that are associated with the current thread, the destructors of objects with static storage duration, and the functions registered with std::atexit are executed concurrently

(emphasis added)

I thought the destructor would be called by the main thread

What makes you think that? C++ does not associate objects with threads. Even a thread local object can be interacted with on another thread through a pointer or reference.

Is there a way to keep the exit(0) call at the lowest level

Yes, don't have static duration std::thread (sub-)objects, especially those which can call exit.

with the destructors being called from the main thread?

Co-ordinate such that the main thread is the one to call exit. Or just return from main

Will exit() or an exception prevent an end-of-scope destructor from being called?

If you call exit, the destructor will not be called.

From the C++ standard (§3.6.1/4):

Calling the function

void exit(int);

declared in <cstdlib> (18.3) terminates the program without leaving the current block and hence without destroying any objects with automatic storage duration (12.4). If exit is called to end a program during the destruction of an object with static storage duration, the program has undefined behavior.

Are Basic Object Destructors Called On Exit()?

According to this link, it does not clean up the object.
Note that if you use non-stack memory, it will call the destructor:

static employee emp1;

Second note. Any time you are using cout for debugging edge cases, timing critical debugging, etc., you should add a cout.flush() right after the coutto ensure your output is printed before it moves on. I have seen many people use cout for debugging crashes and the output never prints because the program terminates before the OS had a chance to print the output.

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

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.

Is it safe to call exit() from a C++ function to terminate the program?

Some claim that exit() terminates the program normally, just as a return 0; would from main

std::exit gets called anyway, as part of standard application lifecycle. Quote from CPPReference:

Returning from the main function, either by a return statement or by
reaching the end of the function performs the normal function
termination (calls the destructors of the variables with automatic
storage durations) and then executes std::exit, passing the argument
of the return statement (or ​0​ if implicit return was used) as
exit_code.



Others claim that exit() doesn't call all the destructors, etc

It's true, but it doesn't cancel the first statement. I.e. if destructors of you classes don't have any side effects that can survive the program, it doesn't matter whether local were destroyed properly or not, since entire memory of your process is freed after program termination. std::exit however calls destructors of objects with static and thread local storage duration:

The destructors of objects with thread local storage duration that are
associated with the current thread, the destructors of objects with
static storage duration, and the functions registered with std::atexit
are executed concurrently

Destructors called upon program termination

It depends on how your program terminates. If it terminates by having main return (either by an explicit return or falling off the end), then yes, any automatic objects in main will be destructed.

But if your program terminates by calling exit(), then main doesn't actually go out of scope and any automatic objects will not be destructed.

Why aren't destructors guaranteed to be called on interpreter exit?

I'm not convinced by the previous answers here.

Firstly note that the example given does not prevent __del__ methods being called during exit. In fact, the current CPythons will call the __del__ method given, twice in the case of Python 2.7 and once in the case of Python 3.4. So this can't be the "killer example" which shows why the guarantee is not made.

I think the statement in the docs is not motivated by a design principle that calling the destructors would be bad. Not least because it seems that in CPython 3.4 and up they are always called as you would expect and this caveat seems to be moot.

Instead I think the statement simply reflects the fact that the CPython implementation has sometimes not called all destructors on exit (presumably for ease of implementation reasons).

The situation seems to be that CPython 3.4 and 3.5 do always call all destructors on interpreter exit.

CPython 2.7 by contrast does not always do this. Certainly __del__ methods are usually not called on objects which have cyclic references, because those objects cannot be deleted if they have a __del__ method. The garbage collector won't collect them. While the objects do disappear when the interpreter exits (of course) they are not finalized and so their __del__ methods are never called. This is no longer true in Python 3.4 after the implementation of PEP 442.

However, it seems that Python 2.7 also does not finalize objects that have cyclic references, even if they have no destructors, if they only become unreachable during the interpreter exit.

Presumably this behaviour is sufficiently particular and difficult to explain that it is best expressed simply by a generic disclaimer - as the docs do.

Here's an example:

class Foo(object):
def __init__(self):
print("Foo init running")

def __del__(self):
print("Destructor Foo")

class Bar(object):
def __init__(self):
print("Bar1 init running")
self.bar = self
self.foo = Foo()

b = Bar()

# del b

With the del b commented out, the destructor in Foo is not called in Python 2.7 though it is in Python 3.4.

With the del b added, then the destructor is called (at interpreter exit) in both cases.



Related Topics



Leave a reply



Submit