当我们离开catch块范围时,是否会调用异常析构函数? (如果我们不重新抛出它)
假设我有A类,并且它的析构函数不是虚拟的。 B继承A. 假设某些函数将B类的对象作为异常抛出, 它被一个捕获块抓住了
catch(A& a){
...
}
如果在超出catch范围时应该调用异常析构函数, 在这种情况下,只会调用基类A的析构函数?
玉米秆: 实时审判导致调用两个类析构函数。
这与我的逻辑相矛盾。解释某人?
答案 0 :(得分:5)
当我们离开catch块范围时,是否会调用异常析构函数? (如果我们不重新抛出它)
是:
[C++11: 15.1/4]:
[..] 在异常的最后剩余活动处理程序以除了重新抛出之外的任何方式退出之后,或者类型{{的最后一个对象引用异常对象的1}}(18.8.5)被破坏,以较晚者为准。 [..]
如果在超出catch范围时应该调用异常析构函数,在这种情况下只会调用基类A的de tor?
No:
std::exception_ptr
答案 1 :(得分:5)
好的,有人已经回答了你的第一个问题。我将专注于这一个:
如果在超出捕获范围时应该调用异常析构函数,在这种情况下,只会调用基类A的转换器?
实现将始终正确地销毁异常对象,而不管它是如何被捕获的。该实现构造了异常对象,因此它知道如何销毁它。这与通过指针调用delete
时不同,因为在这种情况下,有关该点对象的完整类型的信息不完整(可能已在其他地方new
编辑)除非存在虚拟析构函数。
如果不是这种情况,catch (...)
将永远无法运作。
答案 2 :(得分:3)
虽然我没有引用标准,但似乎抛出B
并抓住A&
会导致A
&{39}和{{ 1}}的析构函数被调用。 Live demo:
B
输出:
开始主要范围
开始内部范围
调用throwit()
抓住了例外 B ::一B
A ::〜阿
结束内部范围
结束主要范围
如您所见,两个析构函数都被调用。额外的范围打印非常清楚地显示了调用析构函数的时间(在#include <iostream>
struct A
{
~A() { std::cout << "A::~A" << std::endl; }
};
struct B : public A
{
~B() { std::cout << "B::~B" << std::endl; }
};
void throwit()
{
throw B{};
}
int main()
{
std::cout << "beginning main scope" << std::endl;
{
std::cout << "beginning inner scope" << std::endl;
try
{
std::cout << "calling throwit()" << std::endl;
throwit();
}
catch (A& a)
{
std::cout << "caught exception" << std::endl;
}
std::cout << "ending inner scope" << std::endl;
}
std::cout << "ending main scope" << std::endl;
}
块的末尾)。
答案 3 :(得分:3)
只要标准说对象被销毁,就意味着调用了最正确的派生析构函数。
始终
当你多态删除一个没有虚析构函数的对象,或者你终止(通过delete
运算符或显式析构函数调用)一个不完整类型的对象和正确的析构函数是非平凡的,标准不会说对象被破坏了。它没有说调用基类析构函数。它说你有不确定的行为。