资源获取是初始化“RAII”

发布于 2024-08-25 22:05:19 字数 526 浏览 5 评论 0原文

在下面的示例中,

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 构造函数中进行一些内存分配怎么办?

in the example below

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";
    };
};

I got this example of RAII from one site and ave some doubts. please help.

  1. in the contructor of x we are not considering the scenation "if the memory allocation fails" .
  2. Here for the destructor of Y is safe as in y construcotr is not allocating any memory. what if we need to do some memory allocation also in y constructor?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

画离情绘悲伤 2024-09-01 22:05:19

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

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

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

In the constructor of X, if new fails it throws an exception (std::bad_alloc). This means that the constructor never completes so the object's lifetime never starts so its destructor is never called (there is no object) and there is no mismatch between new[] and delete[]. (X should have a user-declared copy constructor and a user-declared copy assignment operator as the implementation provided ones would break this guarantee if construction succeeds and the object is copied or assigned.)

In Y, if it allocates memory in it's constructor and this allocation is successful then it needs to ensure that this memory is freed if the rest of the construction throws an exception at any point and, if the constructor completes that the memory is freed in the destructor (assuming that the memory is designed to last the length of the lifetime of the object).

To make this easier any allocated memory should be immediately handed to an object whose single responsibility is to free the memory. Having one class manage raw pointers to multiple blocks of allocated memory is a recipe for complicated and error-prone management code.

你的他你的她 2024-09-01 22:05:19

在 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.X
  6. 的析构函数 delete[]new int[]

同样,这里没有资源泄漏。

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

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

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

in the contructor of x we are not considering the scenation "if the memory allocation fails" .

You don't have to. If it fails, the constructor will throw std::bad_alloc. I.e.:

  1. Y constructor is called.
  2. X constructor is called.
  3. The new int[] allocation fails, throwing std::bad_alloc. The memory is never allocated.
  4. Because X never finished constructing, the Y constructor fails and Y never finishes constructing either.

Therefore there are no leaks.

Here for the destructor of Y is safe as in y construcotr is not allocating any memory. what if we need to do some memory allocation also in y constructor?

You still have no problem. Allocation failures will throw std::bad_alloc. That failure is the responsibility of those using your class.

  1. Y constructor is called.
  2. X constructor is called.
  3. The new int[] allocation succeeds.
  4. The Y constructor now fails somehow and needs to throw an exception (for example an allocation failure).
  5. The exception throwing mechanism unwinds the call stack and calls destructors on any local variables, in this case including X.
  6. X's destructor delete[]s the new int[].

Again, no resources are leaked here.

Note that you do need to be wary of multiple allocations. I.e.:

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

NOW we have a resource leak. When the exception is thrown from the constructor, the object is never fully constructed. Since it's never fully constructed, it's never going to have it's destructor called. Therefore we leak r.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文