I want to immediately exit my MFC app in C++. Is exit(0) the best solution? eg. does it prevent destructors from being called, is it threadsafe? etc. Is there a better solution? Thanks.
Yes, exit(0) is the best solution. It will cause the destructors of global objects (and static objects within functions) to run, however it will not cause destructors of stack-allocated or heap-allocated objects to run:
// At global scope
ClassWithDestruct globalObject;
void SomeFunction()
{
static ClassWithDestructor staticObject;
ClassWithDestructor stackObject;
ClassWithDestructor *heapObject = new ClassWithDestructor;
// On the following call to exit(), the destructors of 'globalObject' and
// 'staticObject' will run, but those of 'stackObject' and 'heapObject' will
// NOT run
exit(0);
}
As to whether or not it's thread-safe, that's a hard question to answer: you should not be calling exit simultaneously from multiple threads, you should only call it once. If any destructors run as a result of exit, or any if any functions registered with atexit run, then obviously those functions should be thread-safe if they deal with data that could potentially be being used by other threads.
If your program is exiting normally (say, as a result of the user requesting an exit), you should either call exit or return from main/WinMain, which is equivalent to calling exit. If your program is exiting abnormally (say, as a result of an access violation or failed assertion), you should call either _exit or abort, which do not call any destructors.
If you want to exit immediately, ensuring against running any destructors and such beforehand, then you probably want to call abort(). If you do want destructors to execute, then you probably want to use PostQuitMessage(0);. Either way, exit() is probably the wrong choice.
when a win32 process exits any resource associated with it is cleaned up by the OS, so in order to me it is perfectly ok.
exit(0) exits the process. All memory is cleaned up. On the other hand explicitly managed resources may not be closed. Of course file handles would be closed and stuff in windows buffers will be flushed. However stuff that the application manages will not.
No, it's not a safe way to end your program. Static-storage data and non-local automatic objects will destruct, but local automatic objects will not.
From 18.3/8 in the C++ standard:
The function exit() has additional
behavior in this International
Standard:
First, objects with static storage
duration are destroyed and functions
registered by calling atexit are
called. Non-local objects with static
storage duration are destroyed […].
(Automatic objects are not destroyed
as a result of calling
exit().)[207]) […] A local static
object obj3 is destroyed at the same
time it would be if a function calling
the obj3 destructor were registered
with atexit at the completion of the
obj3 constructor.
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.[209])
[207]: Objects with automatic storage
duration are all destroyed in a
program whose function main()
contains no automatic objects and
executes the call to exit(). Control
can be transferred directly to such a
main() by throwing an exception that
is caught in main().
[209]: Any C streams associated with
cin, cout, etc (27.3) are flushed
and closed when static objects are
destroyed in the previous phase. The
function tmpfile() is declared in
<cstdio>.
On a related note, std::exit(EXIT_SUCCESS) is disturbingly misleading.
Related
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.
edit:
As someone asked, I added some blocks of code for which I would like to terminate the program. I use C++20
HKEY newKey;
RegOpenKey(HKEY_CURRENT_USER, R"(Software\Microsoft\Windows\CurrentVersion\Run)", &newKey);
LONG result = RegSetValueEx(newKey, value, 0, REG_SZ, (LPBYTE)filePath, lstrlen(filePath));
RegCloseKey(newKey);
if(result != ERROR_SUCCESS){
MessageBox(nullptr, "Could not add to startup", "Error", MB_ICONERROR);
exit(1);
}
int i = line.find(':');
if(i == std::string::npos){
MessageBox(nullptr, "File is incorrectly formatted", "Error", MB_ICONERROR);
exit(1);
}
info.open(infoPath);
if(info.fail()){
MessageBox(nullptr, "info.txt did not open", "Error", MB_ICONERROR);
exit(1);
}
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://learn.microsoft.com/en-us/cpp/cpp/program-termination?view=msvc-170
https://cplusplus.com/reference/cstdlib/exit/
Thanks in advance
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
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
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.
In a multithread C++ program, is it possible to use std::exit correctly in the middle of a parallel execution, with other running threads?
In other words, what are the preconditions to use std::exit?
Are third party libraries generally safe for such use?
Note: calling std::exit is the same as returning from an empty block in main:
int main(.....)
{ // nothing here
{
all the real code......
}
return 0;
}
Remark: the focus here is on the other threads; obviously returning from all functions called from main to be able to return means that all the local variables are properly destructed. That's was always true, even in pre standard C++. That isn't the point here as it isn't a thread issue.
Your premis is false. You dont need threads to break stuff with std::exit. From cppreference:
Stack is not unwound: destructors of variables with automatic storage duration are not called.
Hence, for example this will not do the right thing:
int main() {
auto x = some_raii_type_that_writes_to_file_on_destruction("file.ext");
std::exit();
}
When you normally return from main, then...
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.
That being said, std::exit will only perform the following steps (again cppreference:
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, [...]
2) all C streams are flushed and closed
3) files created by std::tmpfile are removed
4) control is returned to the host environment. [...]
Considering that the stack is not unwound (neither of the thread that calls std::exit nor others), you cannot expect some third party library to behave in a "safe" way.
We have some c++ code that can make calls to exit(3) through the users API. My assumption is that we are not properly unwinding stacks and that this considered bad in c++. Also there is a big c++ library involved that must be considered a black box.
I want to patch this, and also have an idea how, but don't know how to observe and compare the change. Can I make this somehow visible? Possibly on OS X?
exit() apparently does some cleanup. This is described in section 18.5 [support.start.term] of the standard, but the frequently correct site www.cplusplus.com summarizes it.
So it says objects with static storage or thread storage will be cleaned up, as will the entire I/O system (files will be flushed, etc).
But there are other ways to exit without running the C++ cleanup. For example, if it is a library that calls exit and it is a C language library (not C++) then it may or may not do the C++ cleanup. Or there are calls to abort or quick_exit. And, too, if you call the OS directly (e.g., ExitProcess() on Windows) then the process exits immediately and no C++ cleanup is done.
If you want to make the behavior visible: Make a object with a destructor that does something interesting - like log a message somewhere. Or maybe when it is constructed it creates a file with a certain name and when destructed it deletes it. Declare an instance this object in your main(). Declare another one (with a different message) at static scope. So now you have an effect observable in your environment.
The following is from 18.5 of N4140 (2014-10-07):
[[noreturn]] void exit(int status)
8 The function exit() has additional behavior in this International Standard:
(8.1) 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).
(8.2) 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.
(8.3) 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.
I've tried to read up on the difference between return EXIT_SUCCESS; from main() and calling exit(EXIT_SUCCESS) from anywhere, and the best resource I've found so far is this answer here on SO. However, there is one detail I'd like to have cleared up.
To me, the most compelling argument against exit() (as laid forward in that post) is that no destructor is called on locally scoped objects. But what does this mean to other objects? What if I'm calling exit() from somewhere else, quite far away on the stack from the main() method, but in block (even a method) that contains only that call, and no variables? Will objects elsewhere on the stack still be destructed?
My use case is this:
I have an application that keeps prompting the user for input until the "quit" command is given (a text-based adventure game). The easiest way to accomplish that, was to map "quit" to a method that simply calls exit(EXIT_SUCCESS). Of course, I could write it so that every action the user can take returns a boolean indicating wether the game should go on or not, and then just return false when I want to quit - but the only time I'd return anything but true is from this method - every other action method would then have to return true just because I wanted to avoid exit(). On the other hand, I create quite a lot of objects and allocate quite a lot of memory dynamically - all of that has to be taken care of by class destructors, so it is crucial that they do run.
What is best practice here? Is this a good case for exit(), or just as bad as in the main method?
if (command == "quit") {
throw QuitGameException();
}
You could throw an exception. An exception would safely unwind the stack and destroy objects in all the callers along the way.
I'm not even gonna read that SO post, because I know what it says. Don't use exit(), so don't.
I know one reason to use exit() - if you're completely doomed anyway and there's no way you can exit nicely. In such case you will not exit with code zero. So, exit() with non-zero when you're about to crash anyway.
In every other case, create variables which let you leave main loops and exit main nice and sane, to clean-up all your memory. If you don't write code like this, you will e.g. never be able to detect all your memory leaks.
Will objects elsewhere on the stack still be destructed?
Nope, exit() does the following (in order):
Objects associated with the current thread with thread storage duration are destroyed (C++11 only).
Objects with static storage duration are destroyed (C++) and functions registered with atexit are called (if an unhandled exception is thrown terminate is called).
All C streams (open with functions in ) are closed (and flushed, if buffered), and all files created with tmpfile are removed.
Control is returned to the host environment
from: http://www.cplusplus.com/reference/cstdlib/exit/
exit() does not unwind the stack, the memory for the whole stack is simply freed, the destructor for individual objects in the stack are not run. Using exit() is safe only when all objects that does not have simple destructors (those that does not deal with external resources) are allocated in the static storage (i.e. global variables or locally scoped static variable). Most programs have files handlers, socket connections, database handlers, etc that can benefit from a more graceful shut down. Note that dynamically allocated object (that does not deal with external resources) does not necessarily need to be deallocated because the program is about to terminate anyway.
exit() is a feature inherited from C, which does not have destructor and so clean up of external resources can always be arranged using atexit(); in general it's very hard to use exit() in C++ safely, instead in C++ you should write your program in RAII, and throw an exception to terminate and do clean ups.
There are various ways of exiting a process:
e.g.: ExitProcess, ExitThread (from the main thread), exit, abort, return from main, terminate.
I'd like to know the effects each method has on static/global/automatic object destruction.
For example, I have a project that crashes (probably due to some deallocation error) when ExitProcess is called, but not when exit() is called. (related to this question, incidentally).
So basically I'd like to know under which circumstances deallocation of the above objects occurs, and in what order (For VC++).
In short: The only totally safe thing to do is to allow main(), or your thread function, to return.
The C++ standard guarantees (3.6.3/1, 18.3) that destructors for global objects (including static objects) will be called if exit() is called, however it explicitly states that destructors for local variables will not be called in this case. exit() will call any functions registered with atexit(), and will also flush and then close any open stdio streams (including at least stdin, stdout, stderr).
Calling abort() is guaranteed not to call local or global destructors. Nor will it call functions registered with atexit() or flush stdio streams.
Calling any Win32 primitive such as ExitProcess() or ExitThread() will certainly not call destructors for local variables, and will almost certainly not call any destructors for global objects, or any functions registered with atexit(). Calling these functions directly in a C++ program is not advised -- basically, these Win32 functions and the C++ runtime library know nothing about each other. In fact, even the MSDN documentation for ExitThread() advises that C++ programs should return from the thread function instead of calling ExitThread().
(It is theoretically possible that the runtime library has specially arranged for ExitProcess() to call global object destructors -- this could be done by always loading a specific DLL whose entry point function will perform these calls, since ExitProcess() will call the entry point function for each loaded DLL with DLL_PROCESS_DETACH -- however to my knowledge, no implementation does this.)
See the source code of ExitProcess() (posted on compuserve, usenet)