在构造函数中抛出异常:析构函数会被调用吗?

5
如果在对象的构造函数中抛出异常,析构函数会被调用吗?还是说这是未定义行为?(这就是我不愿意说我的编译器做了什么的原因。)
struct foo()
{
    foo(){
        throw "bar";
    }
    ~foo(){
        /*am I called*/
    }
};

foo f;
2个回答

4
析构函数不会被调用,因为在构造函数执行完成之前,foo对象并未被视为完全构造(请注意,这意味着如果您在委托给其他构造函数的构造函数中抛出异常,则析构函数将被调用)。从构造函数中抛出异常并不是未定义行为。

这个答案似乎与quantdev的观点相矛盾。 - P45 Imminent
@YogiBear 这个答案是正确的。幸运的是,这对你来说很容易测试。 - Simple
我测试过了,但是我从我的老板那里继承了"未定义行为"的紧张情绪! - P45 Imminent
@YogiBear:这是一个非常明确定义的行为。虽然quantdev给出了错误的答案,但他提供了正确的链接。如果你做得对的话,就不会有UB和内存泄漏(http://www.parashift.com/c++-faq-lite/selfcleaning-members.html)。(好吧,不完全像FAQ所说的那样,因为`auto_ptr`在C++11中已经被弃用了。但任何其他智能指针都可以很好地完成任务。如果您需要在不同的C++版本之间移植,那么[boost::shared_ptr](http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/shared_ptr.htm)就可以胜任。 - DevSolar
如果你需要调用析构函数以释放一些资源,那么你应该将持有该资源的数据成员作为智能指针/其他 RAII 对象。尽管 ~foo 没有被调用,但是由于数据成员已经完全构造,因此数据成员的析构函数仍然会被调用。 - Simple

3
对象的生命周期从其构造函数执行完毕开始。这意味着,在构造函数执行结束之前,该对象并不存在。因此,没有活动对象,也就没有需要调用的析构函数。
因此,除非异常对象的创建引发另一个异常,否则不会出现未定义的行为。在这种情况下,程序会立即中止。
然而,在异常被抛出的函数作用域内声明的其他对象,包括基类子对象、其他成员对象、本地对象以及任何先前作用域中未捕获该异常的其他对象,都将得到适当的销毁。
请查看“堆栈展开”(首选顺序为stackoverflow、google和wikipedia)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接