如果在构造函数中抛出异常,是否会自动删除为对象分配的内存?

时间:2011-01-17 20:38:53

标签: c++

假设有这段代码:

class CFoo
{
public:
    CFoo()
    {
        iBar = new CBar();
    }
private:
    CBar* iBar;
};

....
CFoo* foo = new CFoo();

执行上面的行时,将分配第一个内存来保存CFoo对象。但是如果新的CBar()行引发异常(由于内存不足),系统会自动解除分配先前分配给CFoo对象的内存吗? 我认为它必须,但找不到任何明确的参考说明。如果没有,编码器将如何释放内存,因为它不会被分配给foo?

4 个答案:

答案 0 :(得分:6)

是的,在这种情况下,将释放为CFoo对象分配的内存。

由于分配失败导致的异常导致CFoo构造函数无法成功完成,因此 new-expression 可以保证释放为该CFoo个对象分配的内存

此保证在ISO / IEC 14882:2003的5.3.4 [expr.new] / 17中规定。

请注意,始终建议将动态分配的结果分配给智能指针以确保正确清理。例如,如果CFoo构造函数中还有其他代码并且抛出了异常,则构造函数中先前已成功分配的CBar对象将被泄露。

答案 1 :(得分:3)

是的,但请考虑如果有多个成员指针会发生什么:

class CFoo
{
public:
    CFoo()
    {
        iBar = new CBar();
        iBaz = new CBaz(); // Throws an exception
    }
private:
    CBar* iBar;
    CBaz* iBaz;
};

....
CFoo* foo = new CFoo();

现在CBar对象将被泄露。使用智能指针而不是本机指针可以解决这个问题。

另外,更喜欢使用成员初始化器:

class CFoo
{
public:
    CFoo() : iBar(new CBar())
    {
        // Nothing here
    }
private:
    CBar* iBar;
};

....
CFoo* foo = new CFoo();

答案 2 :(得分:1)

是的 - 内存会自动释放。考虑以下简化的operator of operator new:

template<typename T> T* operator new() {
    void* ptr = nullptr;
    try {
        ptr = ::operator new(sizeof(T));
        return new (ptr) T();
    } catch(...) {
        ::operator delete(ptr);
        throw;
    }
}

答案 3 :(得分:0)

如果你打算依赖编译器提供的operator new,那么在上面的例子中,不会调用析构函数。原因是:当新的CBar()抛出异常时,堆栈展开立即开始发生,并且对象CFoo没有“完全”构造。由于它是半构造对象,因此编译器不会为CFoo调用析构函数。

经验法则:只在C ++中为完全构造的对象调用析构函数