假设有这段代码:
class CFoo
{
public:
CFoo()
{
iBar = new CBar();
}
private:
CBar* iBar;
};
....
CFoo* foo = new CFoo();
执行上面的行时,将分配第一个内存来保存CFoo对象。但是如果新的CBar()行引发异常(由于内存不足),系统会自动解除分配先前分配给CFoo对象的内存吗? 我认为它必须,但找不到任何明确的参考说明。如果没有,编码器将如何释放内存,因为它不会被分配给foo?
答案 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 ++中为完全构造的对象调用析构函数