[英]Crash in destructor when using 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)
{
}
};
請注意,使用return std::shared_ptr<Number>(this);
實現Number::evaluate()
的“明顯”方式return std::shared_ptr<Number>(this);
已損壞,因為它會導致雙重刪除。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.