为什么这段代码没有捕捉到异常?
#include <iostream>
class A
{
private:
public:
A()
{
std::cout << "A::A()" << std::endl;
}
~A()
{
throw 1;
std::cout << "A::~A(int)" << std::endl;
}
};
int main()
{
A* p = nullptr;
try
{
p = new A();
delete p;
}
catch(...)
{
std::cout << "catch(...)" << std::endl;
}
return 0;
}
一般来说,不建议在析构函数中抛出异常。据我了解(我不会指出标准中的特定位置)——事实上,析构函数被声明为
noexcept——这意味着当在它们中生成异常时,terminate.在这里,运行此代码:
如您所见,它被调用
terminate- 因为在不应该出现的地方抛出异常。“我想是的”(c)维尼
不建议从析构函数中抛出异常,原因有很多。
让我们看看你的代码。
如您所知,首先
delete-expression调用析构函数,然后释放内存。如果析构函数抛出异常,那么内存将不会被释放,这将导致泄漏。例如,在实现容器时,不可能提供有关异常安全的任何保证。例如:
假设发生了内存分配。所以旧元素被复制到新的内存区域。如果复制成功,并且在销毁旧对象时抛出了异常,那么我们将得到一部分未销毁的对象和内存泄漏。但是,如果在复制过程中抛出异常,并且向量试图销毁已经构建的对象,并且在销毁它们时会抛出异常,那么我们将得到相同的泄漏,另外一个异常将“飞”得更远。
如果在堆栈展开期间从自动对象的析构函数中抛出异常,则根据标准,这将导致调用
std::terminate这是来自 C++03 的引用,但行为在后续标准中没有改变。
从 C++11 开始,所有析构函数默认都有一个异常规范
noexcept。如果违反此规范,则调用以下命令std::terminate:也就是说,从 C++11 开始,任何离开析构函数
std::terminate的异常都会导致程序被调用并崩溃,从而至少提供了统一的行为和提供任何保证的可能性。可以为析构函数指定不同的异常规范:但同时,如果抛出异常,我们会得到上面指出的所有问题。
底线:离开析构函数的异常会产生很多问题并且不会提供任何好处,因此一般建议是永远不要让异常离开析构函数。