Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching exceptions in destructors

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.

like image 530
abelenky Avatar asked Sep 23 '13 15:09

abelenky


People also ask

What happens if an exception is thrown in the destructor?

Throwing an exception out of a destructor is dangerous. If another exception is already propagating the application will terminate.

Can we have try catch in destructor?

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.

Do exceptions call destructors?

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 destructor that fails?

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.


2 Answers

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.

like image 111
Daniel Frey Avatar answered Sep 26 '22 02:09

Daniel Frey


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(...) {}     } } 
like image 23
Matthieu M. Avatar answered Sep 26 '22 02:09

Matthieu M.