簡體   English   中英

我們什么時候應該使用 std::enable_shared_from_this

[英]When should we use std::enable_shared_from_this

我只知道std::enable_shared_from_this這個鏈接
但是看了下面的代碼,不知道什么時候用。

try {
        Good not_so_good;
        std::shared_ptr<Good> gp1 = not_so_good.getptr();
    } catch(std::bad_weak_ptr& e) {
        // undefined behavior (until C++17) and std::bad_weak_ptr thrown (since C++17)
        std::cout << e.what() << '\n';    
    }

上面的代碼“不太好”,因為在調用getptr()之前沒有現有的shared_ptr 所以好的事情應該是:

std::shared_ptr<Good> gp1 = std::make_shared<Good>(); // having a shared_ptr at the beginning
std::shared_ptr<Good> gp2 = gp1->getptr();

但是,如果我已經有一個shared_ptr對象,為什么我不簡單地編寫這樣的代碼: std::shared_ptr<Good> gp2 = gp1; ,這意味着我根本不需要std::enable_shared_from_this

在我看來,使用std::enable_shared_from_this是為了確保多個shared_ptr對象具有相同的控制塊,這樣我們就可以避免雙重刪除問題 但是如果一開始就必須提醒自己創建一個shared_ptr ,那我為什么不只是提醒自己使用shared_ptr對象來創建一個新的,而不是使用原始指針呢?

關於std::enable_shared_from_this<T>何時有用的提示在其名稱中:當基於某些請求產生對象時,可能需要返回指向對象本身的指針。 如果結果應該是std::shared_ptr<T>則有必要從成員函數中返回這樣的指針,其中通常沒有可訪問的std::shared_ptr<T>

std::enable_shared_from_this<T>派生后,提供了一種獲取std::shared_ptr<T> ,只要給定一個T類型的指針。 但是,這樣做確實假設該對象已通過std::shared_ptr<T>並且如果該對象在堆棧上分配,則會造成混亂:

struct S: std::enable_shared_from_this<S> {
    std::shared_ptr<S> get_object() {
        return this->shared_from_this();
    };
}

int main() {
    std::shared_ptr<S> ptr1 = std::make_shared<S>();
    std::shared_ptr<S> ptr2 = ptr1->get_object();
    // ...
}

在現實場景中,可能存在某種條件,在這種情況下,返回當前對象的std::shared_ptr<T>

有些用例不能像不透明指針那樣使用模板std::shared_ptr<T>

在這種情況下,有這個很有用:

在 some_file.cpp

struct A : std::enable_shared_from_this<A> {};

extern "C" void f_c(A*);
extern "C" void f_cpp(A* a) {
   std::shared_ptr<A> shared_a = a->shared_from_this();
   // work with operation requires shared_ptr
}

int main()
{
    std::shared_ptr<A> a = std::make_shared<A>();
    f_c(a.get());
}

在 some_other.c

struct A;
void f_cpp(struct A* a);
void f_c(struct A* a) {
    f_cpp(a);
}

假設我想表示一個計算樹。 我們將有一個加法表示為一個從表達式派生的類,帶有兩個指向表達式的指針,因此可以遞歸地計算表達式。 但是,我們需要在某個地方結束評估,所以讓我們對數字進行評估。

class Number;

class Expression : public std::enable_shared_from_this<Expression>
{
public:
    virtual std::shared_ptr<Number> evaluate() = 0;
    virtual ~Expression() {}
};

class Number : public Expression
{
    int x;
public:
    int value() const { return x; }
    std::shared_ptr<Number> evaluate() override
    {
        return std::static_pointer_cast<Number>(shared_from_this());
    }
    Number(int x) : x(x) {}
};

class Addition : public Expression
{
    std::shared_ptr<Expression> left;
    std::shared_ptr<Expression> right;
public:
    std::shared_ptr<Number> evaluate() override
    {
        int l = left->evaluate()->value();
        int r = right->evaluate()->value();
        return std::make_shared<Number>(l + r);
    }
    Addition(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right) :
        left(left),
        right(right)
    {

    }
};

住在 Coliru

請注意,使用return std::shared_ptr<Number>(this);實現Number::evaluate()的“明顯”方式return std::shared_ptr<Number>(this); 已損壞,因為它會導致雙重刪除。

暫無
暫無

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

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