当我们走出catch块的作用域时,异常析构函数会被调用吗? (假设我们没有重新抛出它)
假设我有一个类A,它的析构函数不是虚拟的。 B继承A。 假设某个函数抛出了B类对象作为异常, 并且它被catch块捕获。
catch(A& a){
...
}
如果异常析构函数应该在离开catch作用域时被调用,在这种情况下,只有基类A的析构函数将被调用吗?
Cornstalks:实际试验结果表明两个类的析构函数都会被调用。
这与我的逻辑相矛盾。有人能解释一下吗?
当我们走出catch块的作用域时,异常析构函数会被调用吗? (假设我们没有重新抛出它)
假设我有一个类A,它的析构函数不是虚拟的。 B继承A。 假设某个函数抛出了B类对象作为异常, 并且它被catch块捕获。
catch(A& a){
...
}
如果异常析构函数应该在离开catch作用域时被调用,在这种情况下,只有基类A的析构函数将被调用吗?
Cornstalks:实际试验结果表明两个类的析构函数都会被调用。
这与我的逻辑相矛盾。有人能解释一下吗?
如果在 catch 块结束时需要调用异常析构函数,在这种情况下,只会调用基类 A 的析构函数吗?
#include <iostream>
struct A
{
A() { std::cout << "A()"; }
A(const A&) { std::cout << "A(const A&)"; }
A(A&&) { std::cout << "A(A&&)"; }
~A() { std::cout << "~A()"; }
};
struct B : A
{
B() { std::cout << "B()"; }
B(const B&) { std::cout << "B(const B&)"; }
B(B&&) { std::cout << "B(B&&)"; }
~B() { std::cout << "~B()"; }
};
int main()
{
try {
throw B();
}
catch (A&) {
}
}
// Output: A()B()~B()~A()
~B()
和~A()
都被打印出来了...这正是Cornstalks的答案所确认的...只是说一下。 - Super-intelligent Shade~B()
是_throw-expression_中的临时对象,还是被省略(合法),我们看到的是来自catch
的输出。 - Lightness Races in Orbit好的,有人已经回答了你的第一个问题。我会关注这个问题:
如果在catch范围之外调用异常析构函数,那么只会调用基类A的析构函数吗?
无论异常是如何被捕获的,实现都将正确销毁异常对象。实现构造异常对象,因此它知道如何销毁它。与通过指针调用delete不同,在那种情况下,在该点上关于对象的完整类型存在不完全的信息(它可能已经在其他地方进行了new),除非存在虚拟析构函数。
如果不是这样,catch (...)将根本无法工作。
delete
的时候,没有办法将其与同一对象被new
的地方匹配起来。这就是为什么需要虚析构函数,否则代码无法“知道”要调用哪个析构函数。 - Brian Bidelete
可能与new
位置相距甚远一样,catch
也可能与throw
位置相距甚远。需要一个示例和/或标准引用来支持解释。 - Lightness Races in Orbitthrow
将执行转移到某个蹦床,然后跳到 catch
块中。从 catch
块退出时,会有另一个蹦床销毁异常对象(如果没有 exception_ptr
对象引用它)。这些块成对生成,并可以在静态上匹配。至少这是我理解的;我可能对此有所误解。 - Brian Bi虽然我没有引用标准,但似乎抛出B
并捕获A&
会导致A
和B
的析构函数都被调用。 演示链接:
#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;
}
输出结果:
进入主范围
进入内部范围
调用throwit()
捕获异常
B::~B
A::~A
结束内部范围
结束主范围
正如您所看到的,两个析构函数都被调用了。额外的范围打印清楚地显示了析构函数何时被调用(在 catch
块的末尾)。