未捕获的异常数量可以多于一个吗?

dro*_*te7 24 c++ exception c++17

引入int uncaught_exceptions() noexcept;inC++17而不是bool uncaught_exception() noexcept;引发了一个问题:是否可以同时出现多个异常。

根据en.cppreference.com

返回值

  1. 当前线程中未捕获的异常对象的数量。

我试着想象这样一种情况,当它不止一个时。

绞尽脑汁后,我只想到了一个想法:在同一个块内的局部变量throw中放置一些东西。destructortry

但还是不行。

首先,它违反了强加于 s 的规则,destructor迫使他们这样做noexcept。其次,它可以通过 纠正noexcept(false),但它只会跟注terminate而不是在区块中结束catch

所以它并不能解决问题。

最后,在catch方块内扔任何东西都是很常见的,没有什么不寻常的。因为一旦进入该catch块,uncaught_exceptions()就会递减并变为零。

所以我想知道是否有可能想象出这样一种情况,其中uncaught_exceptions()返回的值会超过1

for*_*818 24

您链接的网站上给出了提示:

有时,即使 while 抛出异常也是安全的std::uncaught_exception() == true。例如,如果堆栈展开导致对象被析构,则该对象的析构函数可以运行抛出异常的代码,只要该异常在逃逸析构函数之前被某个 catch 块捕获即可。

使用此方法:我们抛出一个异常,在堆栈展开期间被销毁的对象的析构函数中,我们抛出另一个立即捕获的异常,但是当它在空中时,我们查看未捕获的异常的数量(可以完成通过另一个对象的析构函数,tracker):

#include <iostream>
#include <exception>

struct tracker {
    ~tracker() {
        std::cout << std::uncaught_exceptions() << "\n";
    }
};

struct foo {
    ~foo() {
        try {
            tracker t;
            throw 123;
        } catch(...) {
            std::cout << std::uncaught_exceptions() << "\n";
        }
    }
};


int main() {
    try {
        foo f;
        throw 42;
    } catch(...) {}

}
Run Code Online (Sandbox Code Playgroud)

输出:

2
1
Run Code Online (Sandbox Code Playgroud)

关键点是第二个异常没有逃逸foos 析构函数。要查看两者,我们需要在进入 s 析构函数中的块uncaught_exceptions之前调用。这就是我使用的原因。一旦进入该块,它就会再次返回。catchfootrackercatch1

uncaught_exception == 2如果没有双层堆栈展开,我不知道如何观察。也许这也是这个问题最初被忽视并仅在 c++17 中修复的原因。另一方面,还可以添加更多层以具有uncaught_exception > 2.

  • @unegare 那很好。如果你读过它,我今天就不会学到东西了:P (13认同)
  • @Peter“关键点是第二个异常不会逃脱 foos 析构函数。” 代码中没有析构函数会抛出异常。我不是从析构函数中“抛出”。我将其放入构造函数中并捕获其中。这总是好的,afaik (4认同)
  • @Peter 正是如此。一旦您有一个函数调用在内部某处抛出**并且**捕获异常,那么它只是朝着与我的代码中相同的情况迈出的一小步。您只需在析构函数中调用此函数,析构函数在堆栈展开期间执行,然后就可以了。短时间内有超过 1 个未捕获的异常。顺便说一句,对于控制流来说,异常的实践并不一定是糟糕的,但是在抛出并捕获异常的 1 次调用中,抛出和捕获可能非常遥远,即使在不同的库中也是如此 (2认同)