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:
Static objects are destroyed in reverse order of their creation.
Functions registered with
atexit() are called in
reverse order of registration, once per registration call.
(This isn't actually new.)
The previous two actions are “interleaved,” that is, given this pseudocode:
extern "C or C++" void f1 (void); extern "C or C++" void f2 (void); 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.
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.
#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
exception then the output from
what() will be included.
Any replacement termination function is required to kill the program without returning; this one calls 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 comes from the call to
abort(), of course.
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.