资源获取是初始化"RAII"

use*_*113 1 c++ raii

在下面的例子中

class X
{
    int *r;
public: 
    X() {
        cout << "X is created";
        r = new int[10];
    };
    ~X() {
        cout<< "X is destroyed";
        delete [] r;
    };
};
class Y
{
public: 
    Y() {
        X x;
        throw 44;
    }; 
    ~Y() {
        cout << "Y is destroyed";
    };
};
Run Code Online (Sandbox Code Playgroud)

我从一个站点得到了RAII的这个例子并且有些疑惑.请帮忙.

  1. 在x的构造函数中,我们没有考虑"如果内存分配失败"的情况.
  2. 这里对于Y的析构函数是安全的,因为在y construcotr中没有分配任何内存.如果我们还需要在y构造函数中做一些内存分配怎么办?

CB *_*ley 9

在构造函数中X,如果new失败则抛出异常(std::bad_alloc).这意味着构造从来没有完成这样的对象的生命周期永远不会发生这样的析构函数不会被调用(没有对象)之间不存在失配new[]delete[].(X应该有一个用户声明的拷贝构造函数和一个用户声明的拷贝赋值运算符作为提供的实现,如果构造成功并且复制或分配了对象,则会破坏此保证.)

Y,如果它在它的构造函数中分配内存并且此分配成功,那么它需要确保释放此内存,如果构造的其余部分在任何点抛出异常,并且如果构造函数完成,则在析构函数中释放内存(假设内存设计为持续对象生命周期的长度).

为了使这更容易,任何分配的内存应立即交给一个对象,其唯一的责任是释放内存.让一个类管理指向多个已分配内存块的原始指针是一个复杂且容易出错的管理代码的配方.


Bil*_*eal 8

在x的构造函数中,我们没有考虑"如果内存分配失败"的情况.

你不必.如果失败,构造函数将抛出std::bad_alloc.即:

  1. 调用Y构造函数.
  2. 调用X构造函数.
  3. new int[]分配失败,抛std::bad_alloc.永远不会分配内存.
  4. 因为X从未完成构造,所以Y构造函数失败,Y也从未完成构造.

因此没有泄漏.

这里对于Y的析构函数是安全的,因为在y construcotr中没有分配任何内存.如果我们还需要在y构造函数中做一些内存分配怎么办?

你还没有问题.分配失败将会抛出std::bad_alloc.失败是使用你班级的人的责任.

  1. 调用Y构造函数.
  2. 调用X构造函数.
  3. new int[]分配成功.
  4. Y构造函数现在以某种方式失败并需要抛出异常(例如分配失败).
  5. 异常抛出机制展开调用堆栈并在任何局部变量上调用析构函数,在本例中包括X.
  6. X的析构函数delete[]new int[].

同样,这里没有泄露任何资源.

请注意,您确实需要警惕多个分配.即:

class Foo
{
    int * r;
public:
    Foo() {
        r = new int;
        throw myException;
    };
    ~Foo() {
        delete r;
    };
};
Run Code Online (Sandbox Code Playgroud)

现在我们有资源泄漏.当从构造函数抛出异常时,该对象永远不会完全构造.由于它从未完全构建,因此它永远不会被称为析构函数.因此我们泄漏r.