`enable_shared_from_this`的用处是什么?

fido 332 c++ boost tr1 boost-asio

我在enable_shared_from_this阅读Boost.Asio示例时跑了过来,在阅读完文档之后,我仍然因为如何正确使用它而迷失了方向.有人可以给我一个例子和/或说明何时使用这个课程是有道理的.

1800 INFORMA.. 347

它可以让你获得一个有效的shared_ptr实例this,当你拥有它时this.没有它,你就没有得到一个的方式shared_ptrthis,除非你已经有一个为会员.这个例子来自enable_shared_from_thisboost文档:

class Y: public enable_shared_from_this<Y>
{
public:

    shared_ptr<Y> f()
    {
        return shared_from_this();
    }
}

int main()
{
    shared_ptr<Y> p(new Y);
    shared_ptr<Y> q = p->f();
    assert(p == q);
    assert(!(p < q || q < p)); // p and q must share ownership
}

方法f()返回一个有效的f(),即使它没有成员实例.请注意,您不能简单地这样做:

class Y: public enable_shared_from_this<Y>
{
public:

    shared_ptr<Y> f()
    {
        return shared_ptr<Y>(this);
    }
}

返回的共享指针将具有与"正确"引用不同的引用计数,并且当删除对象时,其中一个将最终丢失并保持悬空引用.

shared_ptr已成为C++ 11标准的一部分.你也可以从那里以及从中获得它.

  • +1.关键点在于,仅仅返回shared_ptr <Y>(this)的"显而易见"技术被打破了,因为这最终创建了具有单独引用计数的多个不同的shared_ptr对象.因此,您必须永远不要从同一个原始指针**创建多个shared_ptr**. (186认同)
  • @MatthewHolder你有这个报价吗?在cppreference.com上我读到"为另一个`std :: shared_ptr`管理的对象构造`std :: shared_ptr`将不会查询内部存储的弱引用,从而导致未定义的行为." (http://en.cppreference.com/w/cpp/memory/enable_shared_from_this) (6认同)
  • 为什么你不能只做`shared_ptr <Y> q = p`? (3认同)
  • 应该注意的是,在_C++ 11和later_中,如果**它继承自`std :: enable_shared_from_this`,那么在_raw pointer_**上使用`std :: shared_ptr`构造函数是完全有效的**.**我不知道**Boost的语义是否已更新以支持此功能. (2认同)

小智.. 187

来自Dobbs博士关于弱指针的文章,我认为这个例子更容易理解(来源:http://drdobbs.com/cpp/184402026):

...这样的代码无法正常工作:

int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);

这两个shared_ptr对象都不知道另一个,所以两者都会在它们被销毁时尝试释放资源.这通常会导致问题.

类似地,如果一个成员函数需要一个shared_ptr拥有被调用对象的对象,它就不能只是动态创建一个对象:

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对象sp1拥有新分配的资源.成员函数S::dangerous中的代码不知道该shared_ptr对象,因此shared_ptr它返回的对象是不同的sp1.复制新shared_ptr对象sp2没有帮助; 当sp2超出范围时,它将释放资源,当sp1超出范围时,它将再次释放资源.

避免此问题的方法是使用类模板enable_shared_from_this.该模板采用一个模板类型参数,该参数是定义受管资源的类的名称.反过来,该类必须从模板中公开派生; 像这样:

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

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

执行此操作时,请记住,您调用的对象shared_from_this必须由shared_ptr对象拥有.这不起作用:

int main()
{
   S *p = new S;
   shared_ptr<S> sp2 = p->not_dangerous();     // don't do this
}

  • 谢谢,这说明问题比目前接受的答案更好地解决了. (12认同)
  • 我很确定最后一行应该是`shared_ptr <S> sp2 = p-> not_dangerous();`因为这里的缺陷是你必须在调用`shared_from_this()之前以正常的方式创建一个shared_ptr第一次!**这很容易出错!在C++ 17之前,在通过正常方式创建一个shared_ptr之前调用`shared_from_this()`是**UB**:`auto sptr = std :: make_shared <S>();`或`shared_ptr <S > sptr(new S());`.值得庆幸的是,从C++ 17开始,这样做会抛出. (4认同)
  • 不好的例子:`S * s = new S(); shared_ptr &lt;S&gt; ptr = s-&gt; not_dangerous();`&lt;-[仅允许在以前共享的对象(即在std :: shared_ptr &lt;T&gt;管理的对象上)调用shared_from_this。否则,该行为是不确定的(直到C ++ 17)(从C ++ 17起,由默认构造的weak_this的shared_ptr构造函数引发)std :: bad_weak_ptr引发。](http://en.cppreference.com/ w / cpp / memory / enable_shared_from_this)。所以现实是它应该被称为“ always_dangerous()”,因为您需要知道它是否已经被共享。 (2认同)
  • @AnorZaken好点。如果您提交了编辑请求以进行修复,这将很有用。我刚刚这样做。对于发布者,另一个有用的事情是不要选择主观的,上下文相关的方法名称! (2认同)

mackenir.. 28

这是我的解释,从坚果和螺栓的角度来看(最高的答案并没有'点击'跟我一起).*请注意,这是调查Visual Studio 2012附带的shared_ptr和enable_shared_from_this的源代码的结果.也许其他编译器以不同的方式实现enable_shared_from_this ...*

enable_shared_from_this<T>添加一个私有weak_ptr<T>实例,T其中包含实例的" 一个真实引用计数 " T.

所以,当你第一次创建一个shared_ptr<T>新的T*时,那个T*的内部weak_ptr被初始化,其引用数为1.新的shared_ptr基本上都支持这个weak_ptr.

T然后,在其方法中,可以调用shared_from_this以获取该实例,shared_ptr<T>该实例返回到相同的内部存储的引用计数.这样,你总是有一个T*存储ref-count的地方,而不是有多个shared_ptr彼此不了解的实例,并且每个人认为他们shared_ptr负责重新计数T并在他们的引用时删除它-count达到零.

  • 换句话说,'enable_shared_from_this`的整个想法一开始是脆弱的,因为要点是能够从`T*`得到`shared_ptr <T>`,但实际上当你得到指针`T*t时"假设任何关于它已经被共享的东西通常是不安全的,并且做出错误的猜测就是UB. (2认同)

归档时间:

查看次数:

80439 次

最近记录:

10 月,3 周 前