`enable_shared_from_this`有什么用处?
我在阅读Boost.Asio示例时遇到了enable_shared_from_this
,在阅读完文档之后,我仍然不知道如何正确使用它。 有人可以给我一个例子和/或解释什么时候使用这个类是有道理的。
它使您能够得到一个有效的shared_ptr
实例,当你拥有this
。 没有它,你将无法得到一个shared_ptr
到this
,除非你已经有一个成员。 来自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对象。 所以我的回答是不正确的。