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

时间:2016-12-28 15:08:08

标签: c++ c++11 shared-ptr smart-pointers

我只知道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';    
    }

上面的代码是&#34;不太好&#34;因为在调用shared_ptr之前没有getptr()。所以好消息应该是:

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对象来创建一个新对象,而不是使用原始指针?

3 个答案:

答案 0 :(得分:6)

有关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>

答案 1 :(得分:2)

还有一些用例,您无法像不透明指针一样使用模板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_file.cpp

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

在some_other.c

Dictionary<string,object>

答案 2 :(得分:2)

假设我想代表一个计算树。我们将添加一个表示为从表达式派生的类,其中包含两个指向表达式的指针,因此可以递归地计算表达式。但是,我们需要在某个地方结束评估,所以让我们自己评估数字。

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

请注意,使用Number::evaluate()实施return std::shared_ptr<Number>(this);的“明显”方式会被破坏,因为它会导致双重删除。