【发布时间】:2010-09-21 10:11:43
【问题描述】:
如果对象在构造函数中抛出异常,会调用基类的析构函数吗?
【问题讨论】:
标签: c++ constructor
如果对象在构造函数中抛出异常,会调用基类的析构函数吗?
【问题讨论】:
标签: c++ constructor
如果在构建过程中抛出异常,所有之前构建的子对象都会被正确销毁。下面的程序证明基地肯定被破坏了:
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 而不是原始指针。)
【讨论】:
是的。规则是构造函数成功完成的每个对象都将在异常时被破坏。例如:
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)。
【讨论】:
来自标准文档,15.3 - 11,
完全构造的基类和对象的成员应在进入函数的处理程序之前销毁 try- 该对象的构造函数或析构函数块。
【讨论】:
当抛出异常时,为所有(子)构造函数成功运行的对象调用析构函数。这扩展到数据成员和基类等。
例如,对于这段代码
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 的构造函数都没有运行成功,所以它们的析构函数没有运行。
【讨论】: