tags:

views:

267

answers:

4

What's the difference between those three, and how shall I end program in case of exception which I can't handle properly?

+1  A: 
  • terminate leaves you the possibility to register what will happen when it is called. Should be one of the other two.
  • exit is a normal exit allowing to specify an exit status. Handlers registered by at_exit() are run
  • abort is an abnormal exit. The only thing which is ran is the signal handler for SIGABRT.
AProgrammer
+4  A: 

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
    }
}
anon
Huh. I had to try this out myself to verify, but you're right that stack unwinding does not necessarily take place for an uncaught exception. I find that surprising.
Tyler McHenry
Why would that be suprising?
John Dibling
John Dibling
To make sure the stack unwinds you should always catch in main. But I would re-throw from the catch. As some OS have the ability to automatically invoke debugging infrastructure if you have compiled in debug.
Martin York
Exceptions that aren't caught even by a top-level handler could invoke a system reporting facility that dumps the process and uploads the exception report for the developers' attention, like Windows Error Reporting, Mac OS X error reports and iPhone application error logs.
JBRWilkinson
@John The reason why it is surprising to me is that, although it makes perfect sense in light of how exceptions are actually implemented, it breaks the abstraction that an exception "propagates up the stack" until a suitable handler is found (or terminate is called). And leaky abstractions, while often unavoidable, are necessarily surprising when encountered.
Tyler McHenry
+9  A: 
  • abort indicates "abnormal" end to the program, and raises the 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. Edit: Per Neil Butterworth's answer, there is a benefit in that the stack is unwound in this case, which is (somewhat surprisingly) not true for an unhandled exception.

Tyler McHenry
+3  A: 
  • 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(1) indicates a successful run of the application.

Daniel
Unsuccessful! In both Unix and DOS, exit(0) indicates success and any other value passed to exit() indicates failure, not the other way around!
Richard Barrell