gpt4 book ai didi

析构函数中的c++异常

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:50:40 24 4
gpt4 key购买 nike

从其他线程,我知道我们不应该在析构函数中抛出异常!但是对于下面的例子,它确实有效。这是否意味着我们只能在一个实例的析构函数中抛出异常?我们应该如何理解这个代码示例!

#include <iostream>
using namespace std;
class A {
public:
~A() {
try {
printf("exception in A start\n");
throw 30;
printf("exception in A end\n");
}catch(int e) {
printf("catch in A %d\n",e);
}
}
};
class B{
public:
~B() {
printf("exception in B start\n");
throw 20;
printf("exception in B end\n");
}
};
int main(void) {
try {
A a;
B b;
}catch(int e) {
printf("catch in main %d\n",e);
}
return 0;
}

输出是:

exception in B start
exception in A start
catch in A 30
catch in main 20

最佳答案

C++17 之前的最佳实践是不要让异常从析构函数中传播。如果析构函数包含 throw 表达式或调用可能抛出的函数,只要捕获并处理抛出的异常而不是从析构函数中转义就可以了。所以你的 A::~A 没问题。

对于 B::~B,您的程序在 C++03 中没有问题,但在 C++11 中却不行。规则是,如果您确实让异常从析构函数中传播出来,并且该析构函数是针对一个自动对象的,该对象直接被堆栈展开销毁,那么std::terminate 将被调用。由于 b 没有作为栈展开的一部分被销毁,从 B::~B 抛出的异常将被捕获。但在 C++11 中,B::~B 析构函数将被隐式声明为 noexcept,因此,允许异常从中传播出去将调用 std::terminate 无条件。

要允许在 C++11 中捕获异常,您可以这样写

~B() noexcept(false) {
// ...
}

不过,在堆栈展开期间可能会调用 B::~B 的问题——在这种情况下,std::terminate 将是叫。因为在 C++17 之前,没有办法判断是否是这种情况,所以建议永远不要让异常传播到析构函数之外。遵守这条规则,你会没事的。

在 C++17 中,可以使用 std::uncaught_exceptions() 检测对象是否在堆栈展开期间被销毁。但你最好知道自己在做什么。

关于析构函数中的c++异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41174167/

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