enable_shared_from_this <S>什么时候有用?

时间:2019-06-13 17:45:24

标签: c++ shared-ptr enable-shared-from-this

我一直在尝试了解从enable_shared_from_this继承的有用性,尽管在那里对该机制的工作做了一些解释。我在那个post上找不到此问题的答案,所以我在这里发布。

在其中一个示例中。下面的示例是一个不好的做法。我知道两个共享指针互不认识的原因,一旦其中一个共享指针超出范围,资源将被破坏。

struct S
{
  shared_ptr<S> dangerous()
  {
     return shared_ptr<S>(this);   // don't do this!
  }
};

int main()
{
   shared_ptr<S> sp1(new S);
   shared_ptr<S> sp2 = sp1->dangerous();
   return 0;
}

我的问题是为什么用户不这样做

 shared_ptr<S> sp2 = sp1;

那还不只是增加参考数量吗?会好吗?是否出于某些原因给出了该示例,以防该类无法访问sp1并需要返回一个shared_ptr

1 个答案:

答案 0 :(得分:2)

核心问题在这里,由于某种原因,并非代码中的每个共享指针都对其余的代码“已知”。

如果您可以访问已给定的shared_ptr,则应始终按照编写时的使用shared_ptr<S> sp2 = sp1;。与使用std::enable_shared_from_this相比,这绝对是更好的选择。

让我们举一个例子:

struct S: std::enable_shared_from_this<S>
{   
    std::shared_ptr<S> getPtr() { return shared_from_this(); }
};  

// Here we have no interface for providing a shared_ptr, maybe
// code that we can't change or maintain or comes as callback from
// a library we want to use
void f( S* s ) 
{   
    // here we have no access to shared_ptr<S>...
    // so we need to have access to the unique counting instance
    // of all other shared_ptr which are pointing to this object
    std::shared_ptr<S> p3 = s->getPtr();
    std::cout << p3.use_count() << std::endl;

    // do some stuff....

}

int main()
{
    std::shared_ptr<S> p1 = std::make_shared<S>();
    std::cout << p1.use_count() << std::endl;

    // This example is useless, as you can directly use p1
    std::shared_ptr<S> p2 = p1->getPtr();
    std::cout << p1.use_count() << std::endl;
    std::cout << p2.use_count() << std::endl;

    // But if we have to use a interface, which is not providing access via shared_ptr like this:
    f(p1.get());
}  

这里要解决的关键问题仅仅是访问公共的“句柄”,该句柄将我们系统IF中的所有其他shared_ptr连接起来!我们根本无法访问任何shared_ptr!

我们无法访问对象中任何现有的shared_ptr的原因可能很多,例如:使用旧的接口,该接口只允许使用原始指针,但我们希望在其他代码中使用回调来使用共享的ptr来自也仅支持原始指针等的库。

使用std::enable_shared_from_this<S>有一些缺点:

您的接口不再可以使用const S*,因为创建新的shared_ptr将修改std::enable_shared_from_this的数据,该数据现在是您的类或结构的基类。还会增加对象的大小。