2010-03-20 92 views
1

在下面的例子中资源获取就是初始化“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"; 
    }; 
}; 

我从一个站点有RAII的这个例子和AVE有些疑惑。请帮忙。

  1. 在x的构造函数中,我们没有考虑“如果内存分配失败”的情况。
  2. 这里的Y的析构函数是安全的,因为在y构造函数没有分配任何内存。如果我们需要在y构造函数中做一些内存分配呢?
+0

请问您可以使用重新格式化代码吗?将其分成单独的行,用间距选择它,然后单击代码示例按钮(大引号旁边的1和0)。 – 2010-03-20 17:31:22

+0

你如何定义“考虑”?如果分配失败,它会抛出,所以在任何情况下都不会将“X”置于半包状态。 – 2010-03-20 17:32:28

+1

我修复了你的代码。一般来说,如果你发布的代码甚至不是有效的C++,那么得到答案将会变得更加困难。 – 2010-03-20 17:35:54

回答

8

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

你不需要。如果失败,构造函数将抛出std::bad_alloc。即:

  1. Ÿ构造函数被调用。
  2. X构造函数被调用。
  3. new int[]分配失败,抛出std::bad_alloc。内存永远不会被分配。
  4. 由于X从未完成构造,所以Y构造函数失败,并且Y从未完成构造。

因此没有泄漏。

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

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

  1. Ÿ构造函数被调用。
  2. X构造函数被调用。
  3. new int[]分配成功。
  4. Y构造函数现在失败了,需要抛出异常(例如分配失败)。
  5. 异常的投掷机构解开调用栈和任何局部变量调用析构函数,在这种情况下,包括十
  6. X的析构函数delete[] S中new int[]

再次,没有资源在这里泄漏。

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

class Foo 
{ 
    int * r; 
public: 
    Foo() { 
     r = new int; 
     throw myException; 
    }; 
    ~Foo() { 
     delete r; 
    }; 
}; 

现在我们有一个资源泄漏。当从构造函数抛出异常时,该对象从未完全构造。由于它从来没有完全构建,它永远不会有它的析构函数调用。因此我们泄漏r

9

X的构造函数中,如果new失败,则抛出异常(std::bad_alloc)。这意味着构造函数永远不会完成,所以对象的生命周期永远不会启动,因此它的析构函数永远不会被调用(没有对象),并且在new[]delete[]之间没有不匹配。 (X应该有一个用户声明的拷贝构造函数和一个用户声明的拷贝赋值操作符,因为如果构建成功并且该对象被复制或分配,将会违反该保证)。

如果它分配内存在它的构造函数中,这个分配是成功的,那么如果构造函数的其余部分在任何时候抛出一个异常,并且如果构造函数完成了内存在析构函数中被释放,那么它需要确保释放这个内存(假设内存是旨在持续对象的生命周期的长度)。

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

+0

+1这个优秀的点*“X应该有一个用户声明的复制构造函数和一个用户声明的复制赋值运算符作为实现提供的将违反此保证,如果构建成功,并且该对象被复制或分配。”* – Nawaz 2011-02-16 08:06:39