构造和销毁失败之间的C ++代码重用

时间:2015-11-16 15:48:21

标签: c++

我有一个包装一些非托管资源的类。它们在构造函数中分配,并根据RAII模式在析构函数中释放。但是,分配不是原子的,并且,如果构造函数的后期失败,则必须在向调用者抛出异常之前释放在早期阶段分配的所有资源。

这个边缘案例代码越来越像破坏者本身。

我知道C ++类能够调用自己的析构函数,并且因为析构函数被实现为处理通过移动操作处于僵尸状态的实例,所以析构函数已经检查资源是否实际已分配试图释放他们。那么,如果构造失败,类是否可以调用它的析构函数?

另一种方法是创建一个名为release()uninitialise()或类似名称的命名方法,并在构造失败时调用该方法,并作为析构函数的主体。

哪种模式更好?

2 个答案:

答案 0 :(得分:5)

比你的任何一个建议更好 - 模式也是为每个成员对象使用RAII,而不仅仅是复合对象。

坚持单一责任原则。一个对象应该只管理单个对象或单个数组的内存。

像你这样的复合对象应该只拥有处理自己内存的RAII对象。如果一个成员的构造成功而另一个成员抛出,那么第一个成员的析构函数将被调用,它将释放它自己的记忆。

此类所有权的标准库中有std::unique_ptr

答案 1 :(得分:2)

除了自己实施RAII之外,您还应该使用实现RAII的构造。

所以不要做这样的事情:

class MyClass
{
public:
    MyClass()
        : buffer_(new char[512])
        , resource_(new Resource)
    {
    }

    ~MyClass()
    {
        delete resource_;
        delete[] buffer_;
    }

private:
    char* buffer_;
    Resource* resource_;
};

你这样做:

class MyClass
{
public:
    MyClass()
        : buffer_(512, 0)
        , resource_(new Resource)
    {
    }

private:
    // std::vector and std::unique_ptr will free up any resources they 
    // acquire in their destructors so I don't have to do anything explicit in mine
    std::vector<char> buffer_;
    std::unique_ptr<Resource> resource_;
};

这样一来,如果构造函数中的任何内容都失败了,那么你就可以确定已经获得的所有先前资源都将被释放。