lui*_*dim 8 c++ destructor exception try-catch language-lawyer
当try块遇到异常时,将取消堆栈堆栈。如果在try块内部创建了对象,则调用析构函数。如果析构函数引发另一个异常,则不会捕获此异常,并且程序将终止。
因此,如果您有:
struct A {
~A () noexcept(false) {
std::cout << "A::~A" << std::endl;
throw std::runtime_error("A::~A ERROR");
}
};
Run Code Online (Sandbox Code Playgroud)
然后您的try-catch块类似于:
try {
A a1;
A a2;
} catch (...) {}
Run Code Online (Sandbox Code Playgroud)
然后,当try块完成时,a2抛出异常的析构函数,捕获异常,然后抛出异常的析构函数a1并终止程序。一切正常。
但是,如果您引入另一个结构,该结构也抛出了析构函数,但从成员继承A或具有A成员实例,事情就会变得混乱。例如,如果您有:
struct B : A {
~B () noexcept(false) {
std::cout << "B::~B" << std::endl;
throw std::runtime_error("B::~B ERROR");
}
};
Run Code Online (Sandbox Code Playgroud)
然后,如果您这样做:
try {
B b;
A a;
} catch (...) {}
Run Code Online (Sandbox Code Playgroud)
预期的结果应该A::~A是称为异常捕获,然后B::~B称为程序终止。但是,相反,在我尝试过的所有编译器中,除MSVC之外,输出为:
A::~A
B::~B
A::~A
Run Code Online (Sandbox Code Playgroud)
抛出的实例后终止调用 std::runtime_error
what(): A::~A ERROR
Run Code Online (Sandbox Code Playgroud)
好像捕获了两个异常,第三个异常终止了程序。
如果定义B为:
struct B {
~B () noexcept(false) {
std::cout << "B::~B" << std::endl;
throw std::runtime_error("B::~B ERROR");
}
A a;
};
Run Code Online (Sandbox Code Playgroud)
我还尝试了其他一些具有更多结构的组合。
不要费心把任何东西放在catch块中,因为该程序甚至永远不会去那里。
是的,我知道理想上析构函数甚至不应该抛出异常。在阅读了一篇有关抛出析构函数的文章之后,这更多是出于好奇。
我认为您观察到的行为取决于实现。从std :: terminate()上的c ++参考(强调我的):
由于以下任何原因导致异常处理失败时,C ++运行时将调用std :: terminate():
1)引发而不捕获异常(在这种情况下,是否完成堆栈的展开是实现定义的)
在第一种情况下,退出范围:
A被调用。std::runtime_error("A::~A ERROR")被抛出。catch(...)。B调用的析构函数。此时std::terminate()称为。但是是否实现定义
a)程序立即终止并提供您期望的输出
要么
b)程序展开堆栈,从而调用基类的析构函数,A然后终止;这就是您所观察到的。
实时查看Coliru上的代码
| 归档时间: |
|
| 查看次数: |
139 次 |
| 最近记录: |