2010-09-21 105 views

回答

15

如果在施工过程中抛出异常,所有先前构造的子对象都将被正确销毁。下面的程序证明该基地是绝对销毁:

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

我不记得 - 如果你没有发现异常,是保证被调用的基类析构函数,还是作为“堆栈展开”的一部分计算,因此它是否实现定义它是否发生或不在未捕获的异常? – 2010-09-21 10:24:10

+0

@Steve:如果没有捕获,我的实现不会破坏基础,所以我猜*它不能保证,但是谁知道......:-) – fredoverflow 2010-09-21 10:31:49

+3

这就是为什么把一个catch和re-throw放在main中强制堆栈被正确解开是个好主意。 – 2010-09-21 10:41:50

9

是的。规则是构造函数成功完成的每个对象都将在异常时被破坏。例如:

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被破坏(但既不Ÿ也不Z)。

5

当一个异常被抛出,析构函数呼吁所有(子)对象,它们的构造进行了成功运行。这扩展到数据成员和基类。

例如,对于这个代码

struct base {}; 

struct good {}; 

struct bad { 
    bad() {throw "frxgl!";} 
}; 

struct test : public base { 
    std::string s; 
    good g; 
    bad b; 
    test() {} 
}; 

之前test的构造被执行时,第一基类的构造函数被调用,那么对于sg,和b构造函数。只有这些成功完成,才会执行test的构造函数。在构建b期间抛出异常时,基类构造函数以及数据成员sg的构造函数已完全执行,因此它们的析构函数已运行。 test本身和b的构造函数尚未成功运行,因此它们的析构函数未运行。

4

从标准文档,15.3 - 11

完全构造基类和对象的成员应输入功能的处理程序之前被破坏试戴构造的 块或该对象的析构函数。

+1

很好的引用,但它不回答这个问题。 – fredoverflow 2010-09-21 10:29:49

+0

@FredOverflow,是啊谢谢...现在更新.. :) – liaK 2010-09-21 10:34:38

相关问题