Home > front end >  Is it safe to call exit() from a C function to terminate the program?
Is it safe to call exit() from a C function to terminate the program?

Time:08-02

I've read several questions here on Stack Overflow, Microsoft docs, and cplusplus.com. Some claim that exit() terminates the program normally, just as a return 0; would from main. Others claim that exit() doesn't call all the destructors, etc. So I was wondering if someone could help. I link the posts I've read about this:

How to end C code

https://cplusplus.com/forum/beginner/4589/

How to exit program execution in C ?

https://docs.microsoft.com/en-us/cpp/cpp/program-termination?view=msvc-170

https://cplusplus.com/reference/cstdlib/exit/

Thanks in advance

CodePudding user response:

For a call to the C standard function ::exit or std::exit, destructors will be called for objects with static storage duration. Note this doesn't apply to other termination functions like _exit(), abort(), TerminateProcess() etc.

The old simple verbiage ([basic.start.term]) from C 03:

Destructors for initialized objects of static storage duration (declared at block scope or at namespace scope) are called as a result of returning from main and as a result of calling exit

In contrast, destructors for automatic storage duration objects are not called by exit() ([basic.start.main]):

Calling the function void exit(int); declared in <cstdlib> terminates the program without leaving the current block and hence without destroying any objects with automatic storage duration

The contrast with abort() is also quite insightful:

Calling the function void abort(); declared in <cstdlib> terminates the program without executing destructors for objects of automatic or static storage duration and without calling the functions passed to atexit().

For dynamically-allocated objects, naturally destructors are only called if the cleanup process for static (and thread-static) storage objects explicitly destroys such objects (typically because they are owned in a smart pointer).

New verbiage: https://eel.is/c draft/basic.start.term still provides for calling destructors, but now contains new rules to handle threads and thread-local objects instead of just static and automatic storage class.

CodePudding user response:

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

CodePudding user response:

It is completely unreasonable to assume a program is going to properly fall all the way out of main() during any form of error handling. In the case of a we should not / can not go any further, professional programs call exit() all the time.

However, if you have objects that NEED to be cleaned up, then you need to implement an atexit handler. See:

https://en.cppreference.com/w/cpp/utility/program/atexit

  • Related