在互联网上查找C ++脑筋急转弯,我找到了这个例子:
#include <iostream>
using namespace std;
class A {
public:
A()
{
cout << "A::A()" << endl;
}
~A()
{
cout << "A::~A()" << endl;
throw "A::exception";
}
};
class B {
public:
B()
{
cout << "B::B()" << endl;
throw "B::exception"; // <- crashes here
}
~B()
{
cout << "B::~B()";
}
};
int main(int, char**) {
try
{
cout << "Entering try...catch block" << endl;
A objectA;
B objectB;
cout << "Exiting try...catch block" << endl;
}
catch (const char* ex)
{
cout << ex << endl;
}
return 0;
}
这就是我认为该计划会做的事情:
然而,当我运行该程序时,它实际上在标有&lt; - 的行处崩溃了。有人可以解释那时究竟发生了什么吗?
答案 0 :(得分:11)
如果你真的在编码,不仅仅是脑力激荡永远不会从析构函数中抛出异常。如果在堆栈展开期间抛出异常,则调用terminate()
。在你的情况下,在处理B的构造函数中抛出的异常时抛出了A的析构函数。
编辑:
更准确(如评论中所示) - 永远不要让异常逃避析构函数。析构函数中捕获的异常没有问题。但是如果在堆栈展开程序中必须处理两个异常 - 导致堆栈展开的异常和在展开期间转义析构函数的异常,std::terminate()
就会出现。
答案 1 :(得分:6)
当B::B()
抛出异常堆栈时,展开开始。调用A::~A()
并抛出另一个未在A::~A()
内捕获的异常。
如果正在进行堆栈展开时另一个异常会离开析构函数,则会调用terminate()并且看起来像程序崩溃。
答案 2 :(得分:4)
C ++中的黄金法则 - 析构函数不应该抛出异常。忽略此规则将导致各种情况下的未定义行为。
答案 3 :(得分:3)
代码崩溃,因为B的C'tor抛出一个异常,然后启动“Stack Unwinding”程序:所有本地对象都被破坏,dus,A的D'tor被调用,并在Stack展开期间抛出异常,然后调用“abort”,因为同时不能有两个例外......
结论:
永远不要从D'tor中抛出异常,因为你可能会在Stack Unwinding期间扔掉它。
答案 4 :(得分:2)
A::~A()
,正是因为该对象超出了范围。这就是RAII工作的原因---它取决于被调用的析构函数,而不管为什么退出作用域。
A::~A()
然后抛出异常。由于B::B()
的异常仍被抛出堆栈,这会导致程序崩溃。
答案 5 :(得分:2)
你应该从不在析构函数中抛出异常。看看this question为什么。