C ++:如果构造函数可能抛出异常,则处理资源(参考FAQ 17.4)

时间:2009-08-04 23:24:33

标签: c++ exception

感谢所有回复。

我重新格式化了我的问题,以便在包含类的构造函数抛出异常后理解成员指针的状态

再次我的示例类:)

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的原始指针有什么不同。

感谢。

4 个答案:

答案 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 ++库就是这样做的。在这种情况下,对象不处于有效状态,并且可以通过另一种方法检查它是否处于有效状态。

通常在构造函数中抛出异常是最好的。

See my answer here for an extended discussion

答案 2 :(得分:1)

如果p的内存分配失败,则不会调用p的析构函数。

答案 3 :(得分:1)

这个问题确实没有任何意义。 new Fred();永远不会返回NULL。它只会成功创建一个Fred对象,或抛出异常。如果它抛出异常,Fred对象永远不会存在,所以它的析构函数不会被调用。