非虚拟析构函数 c++ 的异常
exception with non virtual destructor c++
当我们超出 catch 块作用域时,是否会调用异常析构函数?
(以防我们不重新抛出它)
假设我有 class A,并且它的析构函数不是虚拟的。
B继承了A。
假设某个函数将 B class 的对象作为异常抛出,
它被捕获块捕获
catch(A& a){
...
}
如果在超出catch范围时调用异常析构函数,
在这种情况下,只有基础 class A 的析构函数会被调用?
玉米杆:
调用两个 class 析构函数的现场试验结果。
这与我的逻辑相矛盾。解释某人?
when we go out of catch block scope, does the exception destructor is called? (In case we don't rethrow it)
是:
[C++11: 15.1/4]:
[..] The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of type std::exception_ptr
(18.8.5) that refers to the exception object is destroyed, whichever is later. [..]
if the exception destructor should be called when go out of catch scope, in this case only the base class A's d'tor will be called?
No:
#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&
将导致 A
和 B
的析构函数被调用。 Live demo:
#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;
}
输出:
beginning main scope
beginning inner scope
calling throwit()
caught exception
B::~B
A::~A
ending inner scope
ending main scope
如您所见,两个析构函数都被调用了。额外的范围打印非常清楚地显示析构函数何时被调用(在 catch
块的末尾)。
好的,已经有人回答了你的第一个问题。我将专注于此:
if the exception destructor should be called when go out of catch scope, in this case only the base class A's d'tor will be called?
实现将始终正确销毁异常对象,无论它是如何捕获的。实现构造了异常对象,所以它知道如何销毁它。这与通过指针调用 delete
时不同,因为在那种情况下,此时关于对象的完整类型的信息不完整(它可能已在其他地方被 new
ed)除非存在虚拟析构函数。
如果不是这样,catch (...)
将永远无法工作。
只要标准说一个对象被销毁,就意味着调用了正确的最派生析构函数。
总是。
当你在没有虚拟析构函数的情况下多态删除一个对象,或者你终止(通过 delete
运算符或显式析构函数调用)一个不完整类型的对象并且适当的析构函数是非平凡的,标准不会说那个对象被摧毁了。它并没有说调用了 base class 析构函数。它说你有未定义的行为。
当我们超出 catch 块作用域时,是否会调用异常析构函数? (以防我们不重新抛出它)
假设我有 class A,并且它的析构函数不是虚拟的。 B继承了A。 假设某个函数将 B class 的对象作为异常抛出, 它被捕获块捕获
catch(A& a){
...
}
如果在超出catch范围时调用异常析构函数, 在这种情况下,只有基础 class A 的析构函数会被调用?
玉米杆: 调用两个 class 析构函数的现场试验结果。
这与我的逻辑相矛盾。解释某人?
when we go out of catch block scope, does the exception destructor is called? (In case we don't rethrow it)
是:
[C++11: 15.1/4]:
[..] The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of typestd::exception_ptr
(18.8.5) that refers to the exception object is destroyed, whichever is later. [..]
if the exception destructor should be called when go out of catch scope, in this case only the base class A's d'tor will be called?
No:
#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&
将导致 A
和 B
的析构函数被调用。 Live demo:
#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;
}
输出:
beginning main scope
beginning inner scope
calling throwit()
caught exception
B::~B
A::~A
ending inner scope
ending main scope
如您所见,两个析构函数都被调用了。额外的范围打印非常清楚地显示析构函数何时被调用(在 catch
块的末尾)。
好的,已经有人回答了你的第一个问题。我将专注于此:
if the exception destructor should be called when go out of catch scope, in this case only the base class A's d'tor will be called?
实现将始终正确销毁异常对象,无论它是如何捕获的。实现构造了异常对象,所以它知道如何销毁它。这与通过指针调用 delete
时不同,因为在那种情况下,此时关于对象的完整类型的信息不完整(它可能已在其他地方被 new
ed)除非存在虚拟析构函数。
如果不是这样,catch (...)
将永远无法工作。
只要标准说一个对象被销毁,就意味着调用了正确的最派生析构函数。
总是。
当你在没有虚拟析构函数的情况下多态删除一个对象,或者你终止(通过 delete
运算符或显式析构函数调用)一个不完整类型的对象并且适当的析构函数是非平凡的,标准不会说那个对象被摧毁了。它并没有说调用了 base class 析构函数。它说你有未定义的行为。