当“嵌套堆栈展开”可以吗?

When 'nested stack unwinding' is OK?

提问人:grizzlybears 提问时间:6/7/2022 最后编辑:grizzlybears 更新时间:6/7/2022 访问量:107

问:

据我了解,我们不能从 dtor 抛出异常, 原因是这样说的: “如果在'堆栈展开'中抛出异常,则没有明确的方法来处理'嵌套展开',因此禁止'从 DTOR 抛出'。”

让我感到困惑的是,为了遵守上述规则,我们编写了这样的代码:

#include <stdexcept>
#include <string>
#include <stdio.h>

void some_cleanup_stuff_that_may_throw();

class Bar
{
public:
    virtual ~Bar(){
        try {
            some_cleanup_stuff_that_may_throw();
        }
        catch (std::exception& e){
            fprintf(stderr, "Exception: %s from %s\n", e.what(), __FUNCTION__);
        }
    }

};

//{{ implementation of 'some_cleanup_stuff_that_may_throw'
void level1();
void level2();

void some_cleanup_stuff_that_may_throw()
{
    level1();
}


void level1()
{
    level2();
}

void level2()
{
    throw std::runtime_error("Yes thrown when stack unwinding");
}

//}} implementation of 'some_cleanup_stuff_that_may_throw'



void Foo1()
{
    Bar b1;
    throw std::runtime_error("Let's start stack unwinding");
}

int main()
{ 
    try {
        Foo1();
    }
    catch (std::exception& e){
        fprintf(stderr, "Exception: %s from %s\n", e.what(), __FUNCTION__);
    }
    return 0;
}


因此,在某些情况下,“嵌套堆栈展开”是可能的。

我的问题是:当“嵌套堆栈展开”是“OK”时?

C++ 异常 析构函数 堆栈展开

评论

2赞 Sam Varshavchik 6/7/2022
您可能会惊讶地发现,直到前段时间,还允许从析构函数中抛出(未捕获)异常。它有效地终止了析构函数,然后从那时起开始展开堆栈。
0赞 Goswin von Brederlow 6/7/2022
不,我们做虚拟 ~Bar() try { some_cleanup_stuff_that_may_throw(); } catch (std::exception& e){ fprintf(stderr, “Exception: %s from %s\n”, e.what(), FUNCTION); return; /* 这个异常没问题,不要终止程序 */ } 注意:如果没有返回,异常将被重新抛出,并变成终止调用。您可以在 dtor 中捕获异常,并确定它们是否致命。注意2:我希望这也将捕获父类中的异常。

答:

3赞 user17732522 6/7/2022 #1

在堆栈展开过程中抛出异常是可以的。但是,从堆栈中解展开的对象的析构函数或异常处理机制调用的任何其他函数(例如 catch 参数构造函数)抛出异常会导致调用 。std::terminate

此处的函数抛出应该意味着抛出的异常没有被捕获到其主体(或函数 try-catch 块)中,并且实际上逃逸了该函数。

在您的示例中,没有例外是离开析构函数。所以没有问题。

允许正在处理或正在展开堆栈的嵌套异常。一旦嵌套异常被捕获、处理并且析构函数完成,原始堆栈展开可以继续调用下一个析构函数,再次向上移动堆栈。甚至还有用于此的 API。例如,您可以使用 which 为您提供当前未捕获的异常数。std::uncaught_exceptions()

C++ 运行时的实现只需要确保跟踪当前处于活动状态的所有异常对象。

(我假设您对展开实现的确切实现细节并不感兴趣。如果你是,那么请在问题中澄清这一点。

评论

0赞 grizzlybears 6/7/2022
哇,std::uncaught_exceptions() 很有趣。
0赞 grizzlybears 6/7/2022
我写了大量“尝试抓住守卫”的 dtor,但仍然不确定这是正确的方法,直到我阅读了您的帖子。谢谢你:)