感谢所有回复。
我重新格式化了我的问题,以便在包含类的构造函数抛出异常后理解成员指针的状态
再次我的示例类:)
class Foo
{
public:
Foo()
{
int error = 0;
p = new Fred;
throw error; // Force throw , trying to understand what will happen to p
}
~Foo()
{
if (p)
{
delete p;
p = 0;
}
}
private:
Fred* p;
};
int main()
{
try
{
Foo* lptr = new Foo;
}
catch (...)
{}
}
类foo的consturctor会因某些随机原因而抛出异常。我知道foo的desturctor永远不会被调用,但在这种情况下,p的析构函数会被调用吗?
将p作为提升智能指针而不是指向fred的原始指针有什么不同。
感谢。
答案 0 :(得分:6)
有一个similar question here涵盖了您的要求。
在这种情况下,如果对new
的调用失败,则保证释放指针的内存。如果调用成功,并且构造函数在此之后抛出,则会发生内存泄漏。
不会调用类的析构函数,因为该对象从未完全构造。有两种方法可以解决这个问题。
1)
在构造函数中完全管理异常:
class Foo
{
public:
Foo()
try
{
p = new p;
throw /* something */;
}
catch (...)
{
delete p;
throw; //rethrow. no memory leak
}
private:
int *p;
};
2)
或者使用智能指针。输入构造函数时,已构造其所有成员。并且因为当构造函数抛出并且构造了对象成员时,它们必须被破坏。智能指针修复了:
class Foo
{
public:
Foo() :
p(new int)
{
throw /* something */;
}
private:
std::auto_ptr<int> p;
};
答案 1 :(得分:2)
如果从未分配,则不会。
但是,不是通过new通过错误分配返回NULL
,您将获得异常std :: bad_alloc。
NULL
将由C malloc返回。
如果一个物体没有完全构造,它也是正确的,它也不会被破坏。因此,如果您在构造函数中成功分配堆,然后抛出异常,则会导致内存泄漏。
您还可以考虑使用僵尸状态而不是抛出异常。一些标准的C ++库就是这样做的。在这种情况下,对象不处于有效状态,并且可以通过另一种方法检查它是否处于有效状态。
通常在构造函数中抛出异常是最好的。
答案 2 :(得分:1)
如果p
的内存分配失败,则不会调用p
的析构函数。
答案 3 :(得分:1)
这个问题确实没有任何意义。 new Fred();
永远不会返回NULL。它只会成功创建一个Fred对象,或抛出异常。如果它抛出异常,Fred对象永远不会存在,所以它的析构函数不会被调用。