18

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

上面的代码“不太好”,因为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对象具有相同的控制块,这样我们就可以避免双重删除问题。但是如果我必须shared_ptr在开始时提醒自己创建一个,为什么我不提醒自己使用shared_ptr对象来创建一个新对象,而不是使用原始指针呢?

4

3 回答 3

10

关于何时std::enable_shared_from_this<T>有用的提示在其名称中:当基于某些请求产生对象时,可能需要返回指向对象本身的指针。如果结果应该是 a std::shared_ptr<T>,则有必要从通常无法std::shared_ptr<T>访问的成员函数中返回这样的指针。

派生自std::enable_shared_from_this<T>提供了一种获取std::shared_ptr<T>给定类型指针的方法T。但是,这样做会假设对象已经通过 a 进行管理,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>在现实场景中,可能存在返回当前对象的某种条件。

于 2016-12-28T15:54:02.177 回答
3

在某些用例中,您不能使用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);
}
于 2016-12-28T15:50:50.573 回答
3

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

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()with的“明显”方式return std::shared_ptr<Number>(this);被破坏了,因为它会导致双重删除。

于 2016-12-28T15:51:48.547 回答