什么是`enable_shared_from_this`的用处?
-
23-08-2019 - |
题
我碰到enable_shared_from_this
跑一边读Boost.Asio的例子和阅读,我还是失去了应如何正确地使用的文档后。有人可以给我使用这个类时的一个例子和/或与解释是有道理的。
解决方案
它可以让你得到一个有效的shared_ptr
实例this
,当你已经是this
。没有它,你就没有得到一个shared_ptr
到this
,除非你已经有一个作为成员的方式。从enable_shared_from_this的升压文档本示例的:
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 ++ 11标准部分。您也可以从那里,以及从升压得到它。
其他提示
从上弱指针布斯博士文章中,我认为本实施例中更易于理解(来源: 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_pt
r对象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
}
下面是我的解释,从螺母和螺栓的角度(顶端回答没有“点击”与我)。 *请注意,这是调查与Visual Studio的2012年或许其他编译器实现enable_shared_from_this不同的shared_ptr的和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*
的裁判计数存储,而非使用多个shared_ptr
情况下,不知道对方,彼此相信他们是负责裁判计数shared_ptr
的T
并删除它时,他们的REF-计数达到零。
请注意,使用一个boost :: intrusive_ptr不存在这个问题。 这往往是一个更方便的方法来解决这个问题。
这正是在C + + 11以后相同的:它是使返回this
作为共享自指针this
给你一个原始指针的能力
在其它字,它允许打开这样的代码
class Node {
public:
Node* getParent const() {
if (m_parent) {
return m_parent;
} else {
return this;
}
}
private:
Node * m_parent = nullptr;
};
到该:
class Node : std::enable_shared_from_this<Node> {
public:
std::shared_ptr<Node> getParent const() {
std::shared_ptr<Node> parent = m_parent.lock();
if (parent) {
return parent;
} else {
return shared_from_this();
}
}
private:
std::weak_ptr<Node> m_parent;
};
另一种方式是一个weak_ptr<Y> m_stub
成员添加到class Y
。然后写:
shared_ptr<Y> Y::f()
{
return m_stub.lock();
}
有用的,当你不能改变你是从(例如延长别人的库)派生类。不要忘了初始化成员,例如通过m_stub = shared_ptr<Y>(this)
,其即使在一个构造是有效的。
有确定的,如果有更多的短截线像这样的在继承层次结构中,也不会阻止该对象的破坏。
修改强>作为正确地指出通过用户nobar,代码会破坏ý对象时分配完成和临时变量被破坏。因此,我的答案是不正确。