gpt4 book ai didi

c++ - 是什么导致这种在 try block 展开期间抛出析构函数的奇怪行为?

转载 作者:可可西里 更新时间:2023-11-01 17:55:29 24 4
gpt4 key购买 nike

当 try block 遇到异常时,堆栈将展开。如果在 try block 中创建了一个对象,则调用析构函数。如果析构函数抛出另一个异常,则不会捕获此异常并终止程序。

如果你有:

struct A {
~A () noexcept(false) {
std::cout << "A::~A" << std::endl;
throw std::runtime_error("A::~A ERROR");
}
};

然后你的 try-catch block 是这样的:

try {
A a1;
A a2;
} catch (...) {}

然后当 try block 结束时,a2 的析构函数抛出异常,异常被捕获,然后 a1 的析构函数抛出并终止程序。一切都按预期进行。

但是,如果您引入另一个结构,该结构也抛出析构函数,但继承自 A 或具有 A 的实例作为成员,事情就会变得困惑。例如,如果您有:

struct B : A {
~B () noexcept(false) {
std::cout << "B::~B" << std::endl;
throw std::runtime_error("B::~B ERROR");
}
};

那么如果你这样做:

try {
B b;
A a;
} catch (...) {}

预期的结果应该是 A::~A 被调用,异常被捕获,然后 B::~B 被调用,程序终止。但是相反,在我尝试过的所有编译器中,除了 MSVC,输出是:

A::~A

B::~B

A::~A

在抛出 std::runtime_error 实例后调用终止

  what():  A::~A ERROR

好像捕获了两个异常,第三个异常终止了程序。

如果将 B 定义为:

,也会发生同样的情况:
struct B {
~B () noexcept(false) {
std::cout << "B::~B" << std::endl;
throw std::runtime_error("B::~B ERROR");
}
A a;
};

我还尝试了更多结构的其他组合。

不要在 catch block 中放任何东西,因为程序永远不会去那里。

是的,我知道理想情况下,析构函数甚至不应该抛出异常。看了一篇关于抛出析构函数的文章后,更多的是好奇。

最佳答案

我认为您观察到的行为是依赖于实现的。来自 std::terminate() 上的 c++ 引用(强调我的):

std::terminate() is called by the C++ runtime when exception handling fails for any of the following reasons:

1) an exception is thrown and not caught (it is implementation-defined whether any stack unwinding is done in this case)

在您的第一种情况下,在退出范围时:

  • A 的析构函数被调用。
  • 抛出异常 std::runtime_error("A::~A ERROR")
  • 这样的异常被 catch(...) 捕获。
  • 在展开堆栈时,B 的析构函数也会被调用。
  • 此时 std::terminate() 被调用。但它是否是实现定义的

    a) 程序立即终止并给出你期望的输出

    b) 程序展开堆栈,因此调用基类 A 的析构函数,然后终止;这就是你所看到的。

查看代码live on Coliru

关于c++ - 是什么导致这种在 try block 展开期间抛出析构函数的奇怪行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57304176/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com