簡體   English   中英

如何在構造期間拋出bad_alloc時實現正確的堆棧展開和raii

[英]How to implement proper stack unwinding and raii when thrown a bad_alloc during construction

所以我正在設計一個將要處理大量內存的類,我想確保它在構造函數的內存分配期間出現問題時能正確展開。

這是我得到的:

class foo{
public:
    foo(): var1(nullptr), var2(nullptr){
        try{
        var1 = new int(1);
        var2 = new int(2);
        }
        catch(std::exception &e){
            delete var1;
            delete var2;
            return;
        }
    //Some other things involving these variables
}

如果我只想在構造函數中的某些后續代碼因bad_alloc異常導致錯誤之前想要停止構造此對象,那么我是否正確地在catch塊中進行此返回? 或者catch塊在終止時是否取消構造函數? 我整個事情過於復雜嗎?

我想確保它在構造函數的內存分配期間出現問題時能正確展開。

然后你必須使你的代碼符合“一個類控制一個資源或做一個工作”的想法

#include <memory>

// foo has one job - to manage fooness. 
// It no longer manages memory resources

class foo
{
public:
    foo()
    : var1(new int(1))
    , var2(new int(2))
    {
    }

    std::unique_ptr<int> var1;   // unique_ptr only manages a resource
    std::unique_ptr<int> var2;   // unique_ptr only manages a resource
};

其他正確的初始化形式:

#include <memory>

// foo has one job - to manage fooness. 
// It no longer manages memory resources

class foo
{
public:
    foo()
    : var1(std::make_unique<int>(1))
    , var2(std::make_unique<int>(2))
    {
    }

    std::unique_ptr<int> var1;   // unique_ptr only manages a resource
    std::unique_ptr<int> var2;   // unique_ptr only manages a resource
};

默認值:

#include <memory>

// foo has one job - to manage fooness. 
// It no longer manages memory resources

class foo
{
public:
    // default constructor now implicit

    std::unique_ptr<int> var1 = std::make_unique<int>(1);   // unique_ptr only manages a resource
    std::unique_ptr<int> var2 = std::make_unique<int>(2);   // unique_ptr only manages a resource
};

正確,但慣用不愉快 - 冗余初始化:

#include <memory>

// foo has one job - to manage fooness. 
// It no longer manages memory resources

class foo
{
public:
    foo()
    : var1(nullptr)
    , var2(nullptr)
    {
        var1 = std::make_unique<int>(1);
        var2 = std::make_unique<int>(2);
    }

    std::unique_ptr<int> var1;   // unique_ptr only manages a resource
    std::unique_ptr<int> var2;   // unique_ptr only manages a resource
};

這是沒有構圖的一種方法。 注意沒有收益的所有額外復雜性:

#include <memory>

// foo now has two jobs - to manage fooness, and to manage resources. 
// This adds un-necessary complication, bugs and maintenance overhead

class foo
{
public:
    foo()
    : var1(nullptr)
    , var2(nullptr)
    {
        var1 = new int(1);
        var2 = new int(2);
    }

    foo(const foo& other)
    : var1(nullptr)
    , var2(nullptr)
    {
        if (other.var1) {
            var1 = new int(*(other.var1));
        }

        if (other.var2) {
            var2 = new int(*(other.var2));
        }
    }

    foo(foo&& other) noexcept
    : var1(other.var1)
    , var2(other.var2)
    {
        other.var1 = nullptr;
        other.var2 = nullptr;
    }

    foo& operator=(const foo& other)
    {
        foo tmp(other);
        std::swap(var1, tmp.var1);
        std::swap(var2, tmp.var2);
        return *this;
    }

    foo& operator=(foo&& other) noexcept
    {
        foo tmp(std::move(other));
        std::swap(var1, tmp.var1);
        std::swap(var2, tmp.var2);
        return *this;
    }

    ~foo() noexcept
    {
        delete var1;
        delete var2;
    }

    int* var1;   // doesn't manage anything
    int* var2;   // doesn't manage anything
};

你應該查看智能指針: std::unique_ptr (在這種情況下會很有用)和std::shared_ptr / std::weak_ptr (不是你的例子的正確類型,但很高興知道)。

只要您沒有重新實現某種智能指針,使用它們而不是動態分配,它將為您節省一些麻煩(即使您的示例是正確的並且不會泄漏,只要析構函數是正確的)。

您應該拋出異常而不是返回:應通知調用者構造失敗(如果分配失敗意味着構造函數失敗)。 RAII意味着對象永遠不應處於無效狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM