如果对象在构造函数中抛出异常,是否会调用基类的析构函数?
答案 0 :(得分:17)
如果在构造期间抛出异常,则将正确销毁所有先前构建的子对象。以下程序证明基础肯定被破坏了:
struct Base
{
~Base()
{
std::cout << "destroying base\n";
}
};
struct Derived : Base
{
Derived()
{
std::cout << "throwing in derived constructor\n";
throw "ooops...";
}
};
int main()
{
try
{
Derived x;
}
catch (...)
{
throw;
}
}
输出:
throwing in derived constructor
destroying base
(注意本机指针的析构函数什么也不做,这就是为什么我们更喜欢RAII而不是原始指针。)
答案 1 :(得分:9)
是。规则是构造函数成功完成的每个对象都将在异常时被破坏。 E.g:
class A {
public:
~A() {}
};
class B : public A {
public:
B() { throw 0; }
~B() {}
};
调用~A()。 〜B()未被调用;
编辑:此外,假设您有成员:
struct A {
A(bool t) { if(t) throw 0; }
~A() {}
};
struct B {
A x, y, z;
B() : x(false), y(true), z(false) {}
};
会发生什么:x被构造,y被抛出,x被破坏(但是y和z都没有)。
答案 2 :(得分:5)
当抛出异常时, 析构函数被调用 所有(子) 对象,其构造函数已成功运行 < / strong>即可。这扩展到数据成员和基类。
例如,对于此代码
struct base {};
struct good {};
struct bad {
bad() {throw "frxgl!";}
};
struct test : public base {
std::string s;
good g;
bad b;
test() {}
};
在test
的构造函数执行之前,首先调用基类的构造函数,然后调用s
,g
和b
的构造函数。只有这些成功完成,才会执行test
的构造函数。在构造b
期间抛出异常时,基类构造函数以及数据成员s
和g
的构造函数已完全执行,因此它们的析构函数将被运行。 test
本身和b
的构造函数尚未成功运行,因此它们的析构函数不会运行。
答案 3 :(得分:5)
从标准文档 15.3 - 11 ,
完全构造的基类和对象的成员应该在进入函数的处理程序之前销毁 该对象的构造函数或析构函数的块。