在C ++构造函数失败的情况下处理多个动态资源解除分配

时间:2015-11-30 21:44:27

标签: c++ constructor

如果我在构造函数中使用不同的指针(不在同一个数组中)分配了多个动态资源,那么在没有使用智能指针的情况下,如果它们中的任何一个在构造函数中失败,那么清理它的方法是什么?

我使用下面的代码来处理两个资源案例,但如果以后需要更多资源,它就无法扩展。

任何想法都很受欢迎。

例如,

class Foo {
  private:
     int *p;
     bool is_p_alloc;
     int *q;
     bool is_q_alloc;

   public:
        Foo() 
        try 
          :p(NULL), q(NULL), is_p_alloc(false), is_q_alloc(false)
        { 
           p = new int;
           is_p_alloc = true;
           q = new int;
           is_q_alloc = true;
        }
        catch(...)
        {
           if(is_p_alloc)
           {
              delete p;
              p = NULL;
           }

           if(is_q_alloc)
           {
              delete q;
              q = NULL;
           }

           throw bad_alloc();
        }

};

2 个答案:

答案 0 :(得分:3)

使用单一责任和专用类:

#include <memory>

class Foo
{
    std::unique_ptr<int> p;
    std::unique_ptr<int> q;

public:
    Foo() : p(std::make_unique<int>()), q(std::make_unique<int>()) {}

    Foo(Foo &&) = default;
    Foo & operator=(Foo &&) = default;
};

请记住:每当您发现自己在撰写newdelete或析构函数时,您都无法正确理解您的图书馆。

答案 1 :(得分:1)

所有关于异常处理,堆栈展开和本地保留的资源。 我对您的代码进行了一些更改,并添加了一些注释来表示问题和解决方案。

class Foo {
private:
    int *p;
    bool is_p_alloc;
    int *q;
    bool is_q_alloc;
public:
    Foo() : p(NULL), q(NULL), is_p_alloc(false), is_q_alloc(false)
    {
        try{
            p = new int; // The operator new may throw an exception. If it throws an exception, then following 
                         // expressions it this block won't be executed, so you don't have to worry about them.
            is_p_alloc = true;
            q = new int; // The operator new may throw an exception, but if the previous new operator had already
                         //thrown an exception, then it was not executed anyway.
            is_q_alloc = true;
        }
        catch(...) // Good technique!
        {
            if(is_p_alloc)
            {
                delete p; // Yes, you should delete p, because if new operator in the statement "q = new int;"
                              // throw an exception, then the actual object of Foo is not totally constructed, thus
                              // the destructor of this new object of Foo can not be executed, thus the memory which
                              // is pointed by p won't be deleted from heap.
                p = NULL;
            }
            if(is_q_alloc) // If one of the new operators in the try-block throws an exception, then the the
                               // statement "is_q_alloc = TRUE;" is not executed, so the value of is_q_alloc is false.
                               // is_q_alloc will never be true in this context, and you don't have to delete the
                               // memory pointed by q because if this memory reserved in the heap, then the object of Foo is totally constructed.
            {
                delete q;
                q = NULL;
            }
            throw; // Good technique!
        }
    }
};