views:

612

answers:

3

The C++ standard provides the std::set_terminate function which lets you specify what function std::terminate should actually call. std::terminate should only get called in dire circumstances, and sure enough the situations the standard describes for when it's called are dire (e.g. an uncaught exception). When std::terminate does get called the situation seems analagous to being out of memory -- there's not really much you can sensically do.

I've read that it can be used to make sure resources are freed -- but for the majority of resources this should be handled automatically by the OS when the process exits (e.g. file handles). Theoretically I can see a case for if say, you needed to send a server a specific message when exiting due to a crash. But the majority of the time the OS handling should be sufficient.

When is using a terminate handler the Right Thing(TM)?

Update: People interested in what can be done with custom terminate handlers might find this non-portable trick useful.

A: 

I think the right question would be how to avoid the calls to terminate handler, rather than when to use it.

Cătălin Pitiș
-1, pointless sidestep of the question.
Not Sure
Thanks for the appreciation. But... it is not pointless. Avoiding terminate handler is a good practice.
Cătălin Pitiș
It's crystal clear (to me at least) that the OP already understands that.
Not Sure
+4  A: 

This is just optimistic:

but for the majority of resources this should be handled automatically by the OS when the process exits

About the only resources that the OS handles automatically are "File Handles" and "Memory" (And this may vary across OS's). Practically all other resources (and if somebody has a list of resources that are automatically handled by OS's I would love that) need to be manually released by the OS.

Your best bet is to avoid exit using terminate() and try a controlled shut down by forcing the stack to unwind correctly. This will make sure that all destructors are called correctly and your resources are released (via destructors).

About the only thing I would do is log the problem. So that when it does happened I could go back and fix the code so that it does not happen again. I like my code to unwind the stack nicely for resource deallocation, but this is an opinion some people like abrupt halts when things go badly.

My list of when terminate is called:

In general it is called when the exception handling mechanism cannot find a handler for a thrown exception. Some specific examples are:

  • An exception escapes main()
    • Note: It is implementation defined whether the stack is unwound here. Thus I always catch in main and then rethrow (if I do not explicitly handle). That way I guarantee unwinding of the stack (across all platforms) and still get the benefits of the OS exception handling mechanism.
  • Two exceptions propagating simultaneously.
    • An exception escapes a desatructor while another exception is propagating.
    • The expression being thrown generates an exception
  • An exception before or after main.
    • If an exception escapes the constructor/destructor of a global object.
    • If an exception escapes the destructor of a function static variable. (ie be careful with constructors/destructors of nonlocal static object)
    • An exception escapes a function registered with atexit().
  • A rethrow when no exception is currently propagating.
  • An unlisted exception escapes a method/function that has exception specifier list.
    • via unexpected.
Martin York
anon
I believe Neil is correct. Granted, C++ is not always run on a modern OS ;)
Joseph Garvin
NOT recovered is huge. Its anything not low enough to be managed by the OS. DB connectionc, links to the ISS :-). Even sockets are not handeled very well. On Linux If you kill an application listening on a Socket that socket is still unusable for several minutes before the OS will clean in up. On windows file are not handled particularily nicely. How often have I had to reboot because some dead application is still holding onto a file (the file handle may have been cleaned up, but the file system still thinks the file is being used) stopping me from deleting it.
Martin York
But sockets will be recovered - the pause is inherent in the socket architecture, but is also confugurable. I do a lot of ODBC work and have no problems with database connections not being closed (they are also normally sockets, of course). Similarly, I have no problems with files. Are you still running Windows 3.1, by any chance :-)
anon
Started a question to answer the conundrum. http://stackoverflow.com/questions/1060160/os-resources-automatically-clean-up
Martin York
The pause may be inherent, but it would be 0 if closed correctly. In the DB case not all DB's are socket based (you are relying on an implementation detail (ie socket closure is propogated to a seprate processes that can detect the closure)), this is poor style. What happens when you move to an in-proc DB which is all in memory. As for file I dog food a bit and some experimental FS are not as nice as others.
Martin York
Files are closed when an application dies. Most of the time the file handle is open in another application such as Explorer or even the System process, if it was opened over SMB.
Jimbo
A: 

Similar to a statement made in Martin York's answer, about the only thing I do in a custom terminate handler is log the problem so I can identify and correct the offending code. This is the only instance I find that using a custom terminate handler is the Right Thing.


Since it is implementation-defined whether or not the stack is unwound before std::terminate() is called, I sometimes add code to generate a backtrace in order to locate an uncaught exception1.

1) This seems to work for me when using GCC on Linux platforms.

jschmier