Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting active exceptions in the destructor

I have a class that is using RAII for cleanup in case something goes wrong. This means the class contains a flag, that tells it whether the work has been completed, and if this flag is not set when the constructor is called it is performing it's cleanup tasks and produces a log messages. Now I would like this class to become one step more clever, i.e. it should find out, if the error happened, because the work was abborted (i.e. an exception was thrown and the destructor got called) or because someone was missusing this class and never actually finished the work. This means I would have to find out in the destructor, if an exception is active. If one is found I would produce a log message, possibly printing the content of the exception and then rethrowing it. I am guessing something like this.

Foo::~Foo () {
  try { /* do not know what to put here */ }
  catch( const std::exception & ex ) {
     // produce error in log
     throw;
  }
  catch( ... ) {
    // produce some other log message
    throw;
   }
}

However I am not sure if this would work at all, since the exception is active already before the destructor is called and does not originate from the try block. Also I am using a throw; inside the destructor and throwing an exception at this point is a really bad Idea. So I would not do it, unless the standard guarantees clearly that this case is an exception (no pun intended) to this rule (which I don't know).

So is this possible at all, or should I handle this situation in some other way?

like image 345
LiKao Avatar asked Apr 01 '11 09:04

LiKao


People also ask

What happens when an exception is thrown in a destructor?

When an exception is thrown, destructors of the objects (whose scope ends with the try block) are automatically called before the catch block gets executed. That is why the above program prints “Destructing an object of Test” before “Caught 10“.

Can we call an exception from destructor?

The C++ rule is that you must never throw an exception from a destructor that is being called during the "stack unwinding" process of another exception. For example, if someone says throw Foo(), the stack will be unwound so all the stack frames between the throw Foo() and the } catch (Foo e) { will get popped.

How do you handle errors in the destructor?

9. How to handle error in the destructor? Explanation: It will not throw an exception from the destructor but it will the process by using terminate() function. 10.

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.


1 Answers

You can use std::uncaught_exception() which returns true if an exception has been thrown but a catch has not yet handled it. You can use this check in your destructor to make decisions about what it should or should not do.

A note of caution, good programming guidelines usually dictate that having your destructor behave significantly differently under different circumstances is usually not a good idea. So use this function, but don't abuse it. A common use is to have a destructor that only throws if there is no active uncaught exception (this function returns false). But that type of behavior is generally not good design. If the condition was bad enough to warrant an exception, it probably shouldn't be ignored. And destructors should not throw exceptions anyways.

Example:

Foo::~Foo()
{
    if (std::uncaught_exception()) 
    {
        std::cerr << "Warning: Can't cleanup properly" << std::endl;
        return;
    }
    else
    {
        // ...
    }
}
like image 126
SoapBox Avatar answered Oct 07 '22 22:10

SoapBox