4

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.

WilliamKF
  • 41,123
  • 68
  • 193
  • 295
  • 4
    It sounds like right now would be a really good time to read [GoTW #47](http://www.gotw.ca/gotw/047.htm). – Jerry Coffin Nov 01 '11 at 13:22
  • Construction could fail but destruction could never. There is no point of having exception handling mechanism during object destruction. – Mahesh Nov 01 '11 at 13:23
  • 2
    @Mahesh I think you misunderstood the question. It is not about exception handling in the destructor, but about detecting if a destructor is called due to an exception thrown in the surrounding scope of the object. – Christian Rau Nov 01 '11 at 13:53
  • 2
    To summarize Jerry's article: you can detect if an exception has been thrown, but you can not detect if any given object is being destroyed as a result of the stack being unwound in response to that exception. – Dennis Zickefoose Nov 01 '11 at 14:17

4 Answers4

7

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.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • That is what I thought about throw not working, thanks for confirming. – WilliamKF Nov 08 '11 at 23:13
  • "_whether **the** stack is being unwound due to an exception being thrown_" Well, sometimes there are really **two** stacks: the one being unwound, and the stack used by the destructor of an object destroyed **because** of unwinding. – curiousguy Nov 20 '11 at 02:01
  • It looks like @joaobapt answer has solved this problem for C++17, so that the destructor ~B doesn't think it is being destroyed due an exception. – Mark Lakata Jun 03 '20 at 17:02
2

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.

JoaoBapt
  • 195
  • 1
  • 11
0

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.

Puppy
  • 144,682
  • 38
  • 256
  • 465
-1

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.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
curiousguy
  • 8,038
  • 2
  • 40
  • 58