Reputation: 24675
What's the difference between those three, and how shall I end program in case of exception which I can't handle properly?
Upvotes: 162
Views: 85097
Reputation: 7623
This answer has a lot of useful and correct information about the functions in the original question, but if the exception can't be handled correctly as the OP suggests, it may be a misguided bug report like std::logic_error
, and in that case the the advice to let the exception propagate might not be ideal. It's possible the OP knows they have an unrecoverable condition such as a bug that requires the program to exit.
When a bug is detected the program cannot proceed reliably, and throwing is likely to destroy valuable debugging information you need to find the bug, leave a corrupt state, open a security hole, and hide the bug from developers. When a bug is detected, you want the minimum necessary code to run—maybe some carefully-selected emergency shutdown measures—before exiting and you want to capture as much information as possible about the program state in the crash report or core dump.
Throwing is for conditions whose exact source can be predicted ahead of time and thus has a reliable recovery procedure, like running out of disk space when saving a file or finding invalid user input when parsing. (You also want to know that the error is not likely to be handled in the immediate caller, and that it doesn't happen often enough on the critical path to hurt performance). It is not for situations that demand the program exits.
The main tool we have for exiting in case of bugs is called assert
. Sadly a failed assertion sends you straight to abort
, so there's no chance to take emergency shutdown measures that you might put in a terminate
handler—but you may not need any, and abort
is still better than throwing. assert
also doesn't offer fine enough control over when the check will be performed (debug/release?) nor does it capture enough information about the reason for the check (is this a precondition check or a sanity check, or something else?). Doing exit-on-bug-detection really well requires a suite of assert
replacements that allow control over when they are in effect and capture semantics, and call terminate()
on failure. If you can't manage that, use assert
for bug detection.
Even if it's not a bug, if you needed to to exit, throwing will tempt code further up the stack to try to continue.
Upvotes: 0
Reputation: 76630
abort indicates "abnormal" end to the program, and raises the POSIX signal SIGABRT, which means that any handler that you have registered for that signal will be invoked, although the program will still terminate afterwords in either case. Usually you would use abort
in a C program to exit from an unexpected error case where the error is likely to be a bug in the program, rather than something like bad input or a network failure. For example, you might abort
if a data structure was found to have a NULL pointer in it when that should logically never happen.
exit indicates a "normal" end to the program, although this may still indicate a failure (but not a bug). In other words, you might exit
with an error code if the user gave input that could not be parsed, or a file could not be read. An exit code of 0 indicates success. exit
also optionally calls handlers before it ends the program. These are registered with the atexit
and on_exit
functions.
std::terminate is what is automatically called in a C++ program when there is an unhandled exception. This is essentially the C++ equivalent to abort
, assuming that you are reporting all your exceptional errors by means of throwing exceptions. This calls a handler that is set by the std::set_terminate
function, which by default simply calls abort
.
In C++, you usually want to avoid calling abort
or exit
on error, since you're better off throwing an exception and letting code further up the call stack decide whether or not ending the program is appropriate. Whether or not you use exit
for success is a matter of circumstance - whether or not it makes sense to end the program somewhere other than the return statement in main
.
std::terminate
should be considered a last-ditch error reporting tool, even in C++. The problem with std::terminate
is that the terminate handler does not have access to the exception that went unhandled, so there's no way to tell what it was. You're usually much better off wrapping the entirety of main in a try { } catch (std::exception& ex) { }
block. At least then you can report more information about exceptions that derived from std::exception
(although of course exceptions that do not derive from std::exception
would still end up unhandled).
Wrapping the body of main
in try { } catch(...) { }
isn't much better than setting a terminate handler, because again you have no access to the exception in question. There is at least one benefit, though: whether stack unwinding is done when an exception goes completely uncaught is implementation defined, so if you need guaranteed stack unwinding, this would be a way to get that.
Upvotes: 205
Reputation:
My advice would be not to use any of them. Instead, catch
the exceptions you can't handle in main()
and simply return
from there. This means that you are guaranteed that stack unwinding happens correctly and all destructors are called. In other words:
int main() {
try {
// your stuff
}
catch( ... ) {
return 1; // or whatever
}
}
Upvotes: 1
Reputation: 15020
If your program is multi-threaded, then calling exit()
will most likely result in a crash because global/static std::thread
objects will be attempted to destruct without exiting their threads.
If you want to return an error code and exit the program (more or less) normally, call quick_exit()
in multi-threaded programs.
For abnormal termination (without a possibility for you to specify the error code), abort()
or std::terminate()
can be called.
Note: quick_exit() has not been supported by MSVC++ until version 2015 .
Upvotes: 17
Reputation: 5127
std::abort and std::exit (and more: std::_Exit, std::quick_exit) are just lower level functions. You use them to tell the program what you want it to do exactly: what destructors (and if) to call, what other clean-up functions to call, what value to return, etc.
std::terminate is a higher level abstraction: it is called (by either run-time or you) to indicate that an error in the program occurred and that for some reason it is not possible to handle by throwing an exception. The necessity for that typically occurs when error occurs in the exception mechanism itself, but you can use it any time when you do not want your program to continue beyond the given error. I compiled the full list of situations when std::terminate is called in my post. It is not specified what std::terminate does, because you are in control of it. You can configure the behavior by registering any functions. The limitations you have are that the function cannot return back to the error site and it cannot exit via an exception, but technically you can even start your message pump inside. For the list of useful things that you can do inside, see my other post.
In particular, note that std::terminate is considered an exception handler in contexts where std::terminate is called due to a thrown exception that could not be handled, and you can check what the exception was and inspect it by using C++11 using std::rethrow_exception and std::current_exception. It is all in my post.
Upvotes: 25
Reputation: 870
terminate() is automatically called when an exception occurs that cannot be handled. By default, terminate() calls abort(). You can set a custom handle with set_terminate() function.
abort() sends the SIGABRT signal.
exit() is not necessarily a bad thing. It successfully exits the application, and calls atexit() functions in LIFO order. I don't normally see this in C++ applications, however, I do see it in many unix based applications where it sends an exit code at the end. Usually a exit(0) indicates a successful run of the application.
Upvotes: 6
Reputation: 52274
Upvotes: 5