如何在析构函数中检测异常是否处于活动状态?

时间:2011-11-01 13:17:56

标签: c++ exception destructor stack-unwinding

在C ++中,如何在析构函数的主体中检测堆栈是否因为抛出异常而被解开?一旦检测到,我可以获得对活动异常的引用吗?

我问,因为我想添加一些调试代码,解释为什么会出现某种情况,以及是否是由于例外情况。

4 个答案:

答案 0 :(得分:4)

std::uncaught_exception告诉你堆栈是否因为抛出异常而被解除,这就是你所要求的。

但是,它并没有告诉您您可能想知道的内容:您从中调用析构函数的对象是否处于正在展开的堆栈部分中,或者是否正在被销毁的堆栈部分非惯例地退出作为展开一部分的其他析构函数下面的作用域:

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.
}

与DeadMG和Xeo所说的相反,您无法获得未被捕获的异常的引用。没有操作数的throw重新抛出“当前处理的异常”,也就是说你所处的catch-handler或者catch-handler给你调用的异常。它不会重新抛出未捕获的异常。

答案 1 :(得分:0)

  

在C ++中,如何在析构函数的主体中检测堆栈是否因为抛出异常而被解开?

  

一旦检测到,我可以获得对活动异常的引用吗?

没有

答案 2 :(得分:0)

有一个std::uncaught_exception()功能。但是,关于尝试访问异常对象的唯一有用的事情是重新抛出它并尝试捕获它。一般来说,你不应该从任何析构函数中抛出异常。

答案 3 :(得分:0)

C ++ 17的新std::uncaught_exceptions()呢?我认为您可以构建如下代码:

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
        }
    }
};

在这种情况下,std::uncaught_exceptions()会在调用代码时跟踪未捕获的异常数。可以在its cppreference page上找到更多信息。