【问题标题】:resource acquisition is initialization "RAII"资源获取是初始化“RAII”
【发布时间】:2011-01-29 20:27:49
【问题描述】:

在下面的例子中

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 示例,并提出了一些疑问。请帮忙。

  1. 在 x 的构造函数中,我们没有考虑“如果内存分配失败”的场景。
  2. 这里 Y 的析构函数是安全的,因为在 y 构造函数中没有分配任何内存。如果我们还需要在 y 构造函数中进行一些内存分配怎么办?

【问题讨论】:

  • 您可以使用重新格式化代码吗?将其分成不同的行,带间距,选择它,然后单击代码示例按钮(大引号旁边的 1 和 0)。
  • 你如何定义“考虑”?如果分配失败,它会抛出,所以无论如何你都不会让“X”处于半烤状态。
  • 我修复了你的代码。通常,如果您发布的代码甚至不是有效的 C++,那么获得答案会更加困难。

标签: c++ raii


【解决方案1】:

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

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

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

【讨论】:

  • +1 表示这一点 "X 应该有一个用户声明的复制构造函数和一个用户声明的复制赋值运算符,因为如果构造成功并且对象的实现提供的实现将破坏这个保证被复制或分配。”
【解决方案2】:

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

您不必这样做。如果失败,构造函数将抛出std::bad_alloc。即:

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

因此没有泄漏。

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

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

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

再一次,这里没有资源泄露。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 2013-04-18
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多