`enable_shared_from_this`有什么用处?

我在阅读Boost.Asio示例时遇到了enable_shared_from_this ,在阅读完文档之后,我仍然不知道如何正确使用它。 有人可以给我一个例子和/或解释什么时候使用这个类是有道理的。

它使您能够得到一个有效的shared_ptr实例,当你拥有this 。 没有它,你将无法得到一个shared_ptrthis ,除非你已经有一个成员。 来自enable_shared_from_this boost文档的这个例子:

 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()返回一个有效的shared_ptr ,即使它没有成员实例。 请注意,你不能简单地这样做:

 class Y: public enable_shared_from_this<Y> { public: shared_ptr<Y> f() { return shared_ptr<Y>(this); } } 

这个返回的共享指针将有一个不同的引用计数从“正确的”,其中一个将最终丢失,并保持悬挂引用删除对象时。

enable_shared_from_this也将成为新的C ++ 0x标准的一部分,所以你也可以从那里得到它和boost。

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

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

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

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

同样,如果一个成员函数需要一个拥有被调用对象的shared_ptr对象,它不能仅仅创build一个对象:

 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; } 

这个代码与前面的例子有相同的问题,尽pipe是一个更微妙的forms。 在构build时, shared_pt r对象sp1拥有新分配的资源。 成员函数S::dangerous中的代码不知道该shared_ptr对象,所以它返回的shared_ptr对象与sp1不同。 将新的shared_ptr对象复制到sp2没有帮助; 当sp2超出范围时,它将释放资源,当sp1超出范围时,它将再次释放该资源。

避免这个问题的方法是使用类模板enable_shared_from_this 。 模板采用一个模板types参数,这是定义托pipe资源的类的名称。 反过来,这个阶级必须从模板中公开推导出来; 喜欢这个:

 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 } 

这是我的解释,从一个坚果和螺栓的angular度(顶部的答案没有“点击”与我)。 *请注意,这是调查Visual Studio 2012附带的shared_ptr和enable_shared_from_this的源代码的结果。也许其他编译器以不同的方式实现enable_shared_from_this … *

enable_shared_from_this<T>将一个私有的weak_ptr<T>实例添加到T ,该实例为T实例保存“ 一个真实的引用计数 ”。

所以,当你第一次创build一个shared_ptr<T>到一个新的T *时,T *的内部weak_ptr被初始化为refcount为1.新的shared_ptr基本上回weak_ptr这个weak_ptr

T然后可以在其方法中调用shared_from_this来获得shared_ptr<T>的实例,该实例返回到相同的内部存储的引用计数 。 这样,你总是有一个地方存储T*的引用计数,而不是有多个不知道彼此的shared_ptr实例,每个实例都认为它们是负责T计数的shared_ptr ,当它们的计数达到零时删除它。

请注意,使用boost :: intrusive_ptr不会遇到这个问题。 这通常是解决此问题的更方便的方法。

另一种方法是将weak_ptr<Y> m_stub成员添加到class Y 。 然后写:

 shared_ptr<Y> Y::f() { return m_stub.lock(); } 

有用的,当你不能改变你从类派生(如扩展其他人的图书馆)。 不要忘记初始化成员,例如通过m_stub = shared_ptr<Y>(this) ,即使在构造函数中它也是有效的。

如果在inheritance层次结构中存在更多像这样的存根,那么就不会阻止对象的销毁。

编辑:正如用户nobar指出的那样,当代码完成并且临时variables被销毁时,代码将销毁Y对象。 所以我的回答是不正确的。