【问题标题】:Will the destructor of the base class called if an object throws an exception in the constructor?如果对象在构造函数中抛出异常,会调用基类的析构函数吗?
【发布时间】:2010-09-21 10:11:43
【问题描述】:

如果对象在构造函数中抛出异常,会调用基类的析构函数吗?

【问题讨论】:

    标签: c++ constructor


    【解决方案1】:

    如果在构建过程中抛出异常,所有之前构建的子对象都会被正确销毁。下面的程序证明基地肯定被破坏了:

    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 而不是原始指针。)

    【讨论】:

    • 我不记得了——如果你没有发现异常,是保证调用基类析构函数,还是算作“堆栈展开”的一部分,因此它是实现定义的它是否发生在未捕获的异常上?
    • @Steve:没有捕获,基础不会在我的实现中被破坏,所以我不能保证,但谁知道...... :-)
    • 这就是为什么在 main 中放置一个 catch 和 re-throw 来强制堆栈正确展开是个好主意。
    【解决方案2】:

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

    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)。

    【讨论】:

      【解决方案3】:

      来自标准文档,15.3 - 11

      完全构造的基类和对象的成员应在进入函数的处理程序之前销毁 try- 该对象的构造函数或析构函数块。

      【讨论】:

      • 不错的报价,但它没有回答问题。
      【解决方案4】:

      当抛出异常时,为所有(子)构造函数成功运行的对象调用析构函数。这扩展到数据成员和基类等。

      例如,对于这段代码

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

      在执行test的构造函数之前,首先调用基类的构造函数,然后调用sgb的构造函数。只有当这些成功完成时,test 的构造函数才会被执行。当b的构造过程中抛出异常时,基类构造函数以及数据成员sg的构造函数都已被完全执行,因此它们的析构函数被运行。 test 本身和b 的构造函数都没有运行成功,所以它们的析构函数没有运行。

      【讨论】:

        猜你喜欢
        • 2012-04-15
        • 2011-05-29
        • 2015-07-18
        • 1970-01-01
        • 2012-01-21
        • 2015-12-22
        • 2016-07-18
        • 1970-01-01
        • 2014-08-02
        相关资源
        最近更新 更多