我只知道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()
的"明显"方式被破坏了,因为它会导致双重删除。