Is it possible to make a destructor catch exceptions and then re-throw them?
If so, how would I do that, since there isn't a clear place for a try
statement?
Basically, I want to ideally do:
CMyObject::~CMyObject() { catch(...) // Catch without a try. Possible? { LogSomeInfo(); throw; // re-throw the same exception } // Normal Destructor operations }
Background
I have a large, complex application that is throwing an unhandled exception somewhere. I don't have easy access to main
or the top level message-pump or anything similar, so there's no easy place to catch all unhandled exceptions.
I figure any unhandled exception has to pass through a bunch of destructors as the stack is unwound. So, I'm contemplating scattering a bunch of catch
statements in destructors. Then at least I'd know what objects are in play when the exception is thrown. But I have no idea if this is possible, or advisable.
Throwing an exception out of a destructor is dangerous. If another exception is already propagating the application will terminate.
You must avoid having a destructor that may throw an exception, it's OK to catch and manage them properly. You might care to read N4152, "uncaught exceptions", voted into C++17.
Yes, destructors are guaranteed to be called on stack unwinding, including unwinding due to exception being thrown. There are only few tricks with exceptions that you have to remember: Destructor of the class is not called if exception is thrown in its constructor.
How can I handle a failure in the destructor.? A failure in the constructor can be handled by throwing an exception, where as throwing an exception in the destructor will lead to stack unwinding.
EDIT: You can use std::uncaught_exception
to check if an exception is currently being thrown (i.e. if stack unwinding is in progress due to an exception). It is not possible to catch that exception or otherwise get access to it from your destructor. So if your logging doesn't need access to the exception itself, you can use
CMyObject::~CMyObject() { if(std::uncaught_exception()) { LogSomeInfo(); // No access to exception. } // Normal Destructor operations }
Note that this question was asked in 2013, meanwhile std::uncaught_exception
was replaced with std::uncaught_exceptions
(notice the additional s
at the end) which returns an int
. For a rationale, see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4152.pdf, so if you are using C++17, you should prefer the new version. The above paper also explains why the old std::uncaught_exception
will not work as expected in some situations.
Another option might be std::set_terminate
. This is useful if you want to have a method called when an exception is not caught and about to terminate the program. In the terminate handler, I usually print some information about the exception and a (demangled) backtrace of where it originates from to my log file before finally terminating the program. This is compiler and system specific, but a real helper as it saves a lot of time if you write server processes and often the log file is all you get from ops.
You can use std::uncaught_exception()
which returns true if and only if there is an exception being processed. It has been available since C++98, and is superseded by std::current_exception
which returns a std::exception_ptr
.
However you must be careful not to throw another exception in an unguarded context, otherwise std::terminate
will be caught. Example:
X::~X() { if (std::uncaught_exception()) { try { LogSomeInfo(); // and do something else... } catch(...) {} } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With