我们什么时候应该使用 std::enable_shared_from_this

When should we use std::enable_shared_from_this

我刚知道 std::enable_shared_from_this 形式 this link
但是看了下面的代码,不知道什么时候用

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

上面的代码是"not so good",因为在调用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对象拥有相同的控制块,这样我们就可以避免the double-delete problem。但是,如果我必须提醒自己一开始就创建一个 shared_ptr,为什么我不提醒自己使用 shared_ptr 对象来创建一个新对象,而不是使用原始指针?

有些用例不能使用模板 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 的加法,该表达式派生自具有两个指向表达式的指针的表达式,因此可以递归地计算表达式。但是,我们需要在某处结束评估,所以让数字自行评估。

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)
    {

    }
};

Live on Coliru

请注意,使用 return std::shared_ptr<Number>(this); 实现 Number::evaluate() 的 "obvious" 方式已损坏,因为它会导致双重删除。

有关 std::enable_shared_from_this<T> 何时有用的提示在其名称中:当根据某些请求生成对象时,可能需要 return 指向对象本身的指针。如果结果应该是 std::shared_ptr<T>,则有必要从成员函数中 return 这样的指针,其中通常没有 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> 到当前对象 returned。