Termination

Termination Handlers

Not many changes here to <cstdlib>. You should note that the abort() function does not call the destructors of automatic nor static objects, so if you're depending on those to do cleanup, it isn't going to happen. (The functions registered with atexit() don't get called either, so you can forget about that possibility, too.)

The good old exit() function can be a bit funky, too, until you look closer. Basically, three points to remember are:

  1. Static objects are destroyed in reverse order of their creation.

  2. Functions registered with atexit() are called in reverse order of registration, once per registration call. (This isn't actually new.)

  3. The previous two actions are interleaved, that is, given this pseudocode:

      extern "C or C++" void f1 ();
      extern "C or C++" void f2 ();
    
      static Thing obj1;
      atexit(f1);
      static Thing obj2;
      atexit(f2);
    

    then at a call of exit(), f2 will be called, then obj2 will be destroyed, then f1 will be called, and finally obj1 will be destroyed. If f1 or f2 allow an exception to propagate out of them, Bad Things happen.

Note also that atexit() is only required to store 32 functions, and the compiler/library might already be using some of those slots. If you think you may run out, we recommend using the xatexit/xexit combination from libiberty, which has no such limit.

Verbose Terminate Handler

If you are having difficulty with uncaught exceptions and want a little bit of help debugging the causes of the core dumps, you can make use of a GNU extension, the verbose terminate handler.

The verbose terminate handler is only available for hosted environments (see Configuring) and will be used by default unless the library is built with --disable-libstdcxx-verbose or with exceptions disabled. If you need to enable it explicitly you can do so by calling the std::set_terminate function.

#include <exception>

int main()
{
  std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
  ...

  throw anything;
}

The __verbose_terminate_handler function obtains the name of the current exception, attempts to demangle it, and prints it to stderr. If the exception is derived from std::exception then the output from what() will be included.

Any replacement termination function is required to kill the program without returning; this one calls std::abort.

For example:

#include <exception>
#include <stdexcept>

struct argument_error : public std::runtime_error
{
  argument_error(const std::string& s): std::runtime_error(s) { }
};

int main(int argc)
{
  std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
  if (argc > 5)
    throw argument_error("argc is greater than 5!");
  else
    throw argc;
}

With the verbose terminate handler active, this gives:

   
   % ./a.out
   terminate called after throwing a `int'
   Aborted
   % ./a.out f f f f f f f f f f f
   terminate called after throwing an instance of `argument_error'
   what(): argc is greater than 5!
   Aborted
   
   

The 'Aborted' line is printed by the shell after the process exits by calling abort().

As this is the default termination handler, nothing need be done to use it. To go back to the previous silent death method, simply include <exception> and <cstdlib>, and call

     std::set_terminate(std::abort);
   

After this, all calls to terminate will use abort as the terminate handler.

Note: the verbose terminate handler will attempt to write to stderr. If your application closes stderr or redirects it to an inappropriate location, __verbose_terminate_handler will behave in an unspecified manner.