4

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

我问是因为我想添加一些调试代码来解释为什么会出现某种情况以及是否是由于异常引起的。

4

4 回答 4

7

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没有操作数会重新抛出“当前处理的异常”,也就是说,您所在的异常处理程序或其捕获处理程序调用了您。它不会重新抛出未捕获的异常。

于 2011-11-03T02:14:50.847 回答
2

那么 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()在调用代码时跟踪未捕获异常的数量。更多信息可以在其 cppreference 页面上找到。

于 2018-08-07T12:41:35.203 回答
0

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

于 2011-11-01T13:33:16.877 回答
-1

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

不是。

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

不。

于 2011-11-01T13:29:24.377 回答