【问题标题】:Exception thrown in a constructor: is the destructor called? [duplicate]构造函数中抛出的异常:是否调用了析构函数? [复制]
【发布时间】:2014-08-02 21:39:08
【问题描述】:

如果在对象的构造函数中抛出异常,那么会调用析构函数吗?还是未定义的行为? (这就是为什么我不愿意说我的编译器做了什么。)

struct foo()
{
    foo(){
        throw "bar";
    }
    ~foo(){
        /*am I called*/
    }
};

foo f;

【问题讨论】:

    标签: c++


    【解决方案1】:

    不会调用析构函数,因为 foo 对象在构造函数完成执行之前不会被认为是完全构造的(请注意,这意味着如果你抛出一个委托给不同构造函数的构造函数,那么析构函数 被称为)。从构造函数中抛出不是未定义的行为。

    【讨论】:

    • 这个答案似乎是 quantdev 的
    • @YogiBear 这个答案是正确的。幸运的是,这很容易让您测试自己。
    • 我确实测试过它,但我继承了我老板的“未定义行为”紧张!
    • @YogiBear:这是一个非常明确的行为。虽然 quantdev 给出了错误的答案,但他给出了正确的链接。没有 UB,也没有内存泄漏if you do it right。 (好吧,不像常见问题解答所述,因为 auto_ptr 在 C++11 中已弃用。但任何其他 smart pointers 都可以。如果您需要跨 C++ 版本移植,boost::shared_ptr 可以。
    • 如果您需要调用析构函数来释放某些资源,那么您应该使持有该资源的数据成员成为智能指针/其他一些 RAII 对象。虽然~foo 没有被调用,但数据成员的析构函数被调用,因为数据成员已经完全构造。
    【解决方案2】:

    对象的生命周期从其构造函数完成执行开始。这意味着,在构造函数执行结束之前,该对象从未存在过。因此,没有活动对象,因此没有可调用的析构函数。

    因此,没有未定义的行为,除非创建异常对象引发另一个异常。在这种情况下,程序会立即中止。

    但是,在异常被适当销毁之前完全构造的任何其他对象,包括基础子对象、其他成员对象、在抛出异常的函数的同一范围内声明的本地对象,以及之前范围内没有的任何其他对象捕获该异常。

    检查一下,stack unwinding(在 stackoverflow、google 和 wikipedia 上,按优先顺序)。

    【讨论】:

      猜你喜欢
      • 2012-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-28
      • 2013-07-13
      • 2014-08-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多