How can I detect whether an exception is active during destructor?

1.3k views Asked by At

In C++, how can I detect in the body of my destructor whether the stack is being unwound due to an exception being thrown? Once detected, can I get a reference to the active exception?

I ask because I'd like to add some debugging code that explains why a certain situation may arise and whether it is due to exceptions or not.

4

There are 4 answers

3
Steve Jessop On BEST ANSWER

std::uncaught_exception tells you whether the stack is being unwound due to an exception being thrown, which is what you asked.

However, it doesn't tell you what you probably want to know: whether the object whose destructor you call it from, is in the part of the stack that's being unwound, or the part of the stack that's being destroyed normally due to non-exceptionally exiting a scope beneath some other destructor that is part of the unwind:

struct A {
    ~A();
};

struct B {
    ~B();
}

int main() {
    try {
        A a;
        throw 1;
    } catch(...) {}
}

A::~A() {
    std::uncaught_exception(); // true
    B b;
}

B::~B() {
    std::uncaught_exception(); // also true, but "b" isn't being "unwound",
      // because ~A() returned, it didn't throw.
}

Contrary to what DeadMG and Xeo say, you cannot get a reference to an exception that has not been caught. throw with no operand rethrows the "currently handled exception", that is to say an exception whose catch-handler you are in, or whose catch-handler has called you. It does not rethrow an uncaught exception.

0
curiousguy On

In C++, how can I detect in the body of my destructor whether the stack is being unwound due to an exception being thrown?

Not.

Once detected, can I get a reference to the active exception?

No.

3
Puppy On

There is a std::uncaught_exception() function. However, about the only useful thing you can do to attempt to gain access to the exception object is rethrow it and try to catch it. You should never throw exceptions from any destructor, in general.

0
JoaoBapt On

What about C++17's new std::uncaught_exceptions()? I think you can build a code that looks like this:

class ExceptionSentinel
{
    int prev_uncaught;

public:
    ExceptionSentinel() : prev_uncaught(std::uncaught_exceptions()) {}

    ~ExceptionSentinel()
    {
        int cur_uncaught = std::uncaught_exceptions();
        if (cur_uncaught > prev_uncaught)
        {
            // ... ExceptionSentinel is being destructed by an stack unwinding process
        }
        else
        {
            // ... Normal destruction of ExceptionSentinel
        }
    }
};

In this case, std::uncaught_exceptions() tracks the number of uncaught exceptions by the time the code is called. More info can be found on its cppreference page.