来自 boost::shared_ptr 的 boost 文档:
因为实现使用引用计数,shared_ptr 实例的循环不会被回收。例如,如果 main() 持有一个 shared_ptr 给 A,它直接或间接持有一个 shared_ptr 回 A,A 的使用计数将为 2。原始 shared_ptr 的破坏将使 A 悬空,使用计数为 1。使用 weak_ptr 来“打破循环。”
我无法理解这一段,您能否提供这种情况的最小示例并解释后果。
来自 boost::shared_ptr 的 boost 文档:
因为实现使用引用计数,shared_ptr 实例的循环不会被回收。例如,如果 main() 持有一个 shared_ptr 给 A,它直接或间接持有一个 shared_ptr 回 A,A 的使用计数将为 2。原始 shared_ptr 的破坏将使 A 悬空,使用计数为 1。使用 weak_ptr 来“打破循环。”
我无法理解这一段,您能否提供这种情况的最小示例并解释后果。
智能指针是如何工作的?他们记住count
指向对象的智能指针,并count
在新的共享指针控制对象时增加它,并count
在共享指针失去对对象的控制时减少它。
假设你有一个类:
class A{
public:
A(){std::cout << "Object created" << std::endl;}
~A(){std::cout << "Object destroyed" << std::endl;}
void setSibling(boost::shared_ptr<A> &sibling){
m_sibling = sibling;
}
private:
boots::shared_ptr<A> m_sibling;
};
和一个 foo():
void foo(){
//count increases from 0 to 1 (ptr take control on instance of A)
boost::shared_ptr<A> ptr(new A);
//count increases from 1 to 2 (m_sibling take control on instanse of A)
ptr->setSibling(ptr);
//count decreases from 2 to 1
//(ptr is destroyed and lose control on instance of A)
return;
}
当调用 ~A() 时 m_sibling 将失去控制,但只有当所有共享指针都失去控制时才会调用 ~A()。因此,在调用 foo 之后,您无法访问 A 的该实例。但是计数为 1,并且共享指针不会删除该对象,因此存在内存和资源泄漏。
请参阅 in boost 的文档weak_ptr
以了解如何将它们与shared_ptr
.
简而言之:弱指针就像共享指针但不增加count
. 如果你有一个从shared_ptr
被销毁对象创建的weak_ptr 实例,如果你尝试访问原始指针,weak_prt 实例将抛出异常(不会发生段错误)。boost 文档中有一个示例如何weak_prt
正确使用 usingweak_ptr::lock()
方法。
想象一个宝藏。
你的朋友拿了一个箱子,往里面放了一些金子。他还制作了一张地图。
这是一张神奇的地图,有一个条款:如果你烧掉最新的地图,宝藏和黄金都没有了。
你的朋友把地图放在金子正上方的箱子里,为你制作第二张地图,然后用里面的第一张地图关闭箱子。
他给了你第二张地图,然后带着宝藏消失了。
问题是:如果你烧掉你的地图会发生什么?
答案:没什么,宝物还在某处。
为什么?因为最新的地图副本还在宝箱里!
这是一个示例(请注意,~A
此处从未调用过):
#include <boost/shared_ptr.hpp>
#include <iostream>
using boost::shared_ptr;
struct A
{
~A()
{
std::cout << "~A()" << std::endl;
}
void set_shared_ptr(const shared_ptr<A> &p)
{
p_ = p;
}
shared_ptr<A> p_;
};
int main()
{
shared_ptr<A> q(new A);
q->set_shared_ptr(q);
q.reset();
}
来自Boost 文档
因为实现使用引用计数,shared_ptr 实例的循环不会被回收。
你写:
我无法理解这一段
那挺好的; 那是因为你很聪明。这一段毫无意义。如果你认为你明白了,那就意味着你没有。
循环不能被回收,好吧,因为存在循环依赖!在回收循环的其余部分之前,不能回收循环的任何部分,因此您必须在销毁开始之前销毁每个对象。如果你有循环依赖,这是你程序设计失败的一部分。不要试图责怪智能指针(或引用计数)。
基本依赖问题的任何部分都与智能指针的实现细节没有任何关系;它是由拥有智能指针的定义引起的:在(最后一个)拥有指针的析构函数开始运行之前,拥有的对象不会被销毁。
当然,独占所有权智能指针也是如此,std::unique_ptr
它甚至没有引用计数!
使用weak_ptr 来“打破循环”。
不。避免循环。你不能“打破”一个循环。没有所谓的“打破”循环。
Boost 的文档在这里比没用还糟糕。这很危险。它在这样一个级别上混合了不变量和实现,它表明对智能指针语义的理解非常糟糕。
它讲述了很多关于虚假信息和反模式自我复制的能力!