weak_ptr是如何工作的?

我明白如何使用weak_ptrshared_ptr 。 通过计算对象中引用的数量,我明白shared_ptr是如何工作的。 weak_ptr如何工作的? 我试着通过boost源代码阅读,并且我不太熟悉提高,以了解它使用的所有东西。

谢谢。

shared_ptr使用额外的“计数器”对象(又名“共享计数”或“控制块”)来存储引用计数。 (顺便说一句:“counter”对象也存储删除者。)

每个shared_ptrweak_ptr包含一个指向实际指针的指针,第二个指向“counter”对象的指针。

为了实现weak_ptr ,“counter”对象存储两个不同的计数器:

  • “使用次数”是指向对象的shared_ptr实例的数量。
  • “弱计数”是指向对象的weak_ptr实例的数量,如果“使用计数”仍> 0,则加1。

当“使用计数”达到零时,指针被删除。

当“弱计数”达到零(这意味着“使用计数”也必须为零,参见上文)时,“计数器”辅助对象被删除。

当您尝试从weak_ptr获取shared_ptr ,该库自动检​​查“使用计数”,如果大于0,则会将其增加。 如果成功,你得到你的shared_ptr 。 如果“使用计数”已经为零,您将获得一个空的shared_ptr实例。


编辑 :现在,为什么他们添加一个弱计数,而不是只释放“计数器”对象,当两个计数下降到零? 好问题。

当“使用计数”和“弱计数”都下降到零时,可以select删除“计数器”对象。 这是第一个原因:在每个平台上检查两个(指针大小的)计数器是不可能的,甚至在这个地方,检查一个计数器也比较复杂。

另一个原因是,删除程序必须保持有效,直到完成执行。 由于删除者存储在“counter”对象中,这意味着“counter”对象必须保持有效。 考虑如果有一个shared_ptr和一个weak_ptr指向某个对象会发生什么情况,并且它们在并发线程中同时被重置。 让我们先说shared_ptr 。 它将“使用次数”减less到零,并开始执行删除程序。 现在weak_ptr将“弱计数”减小到零,并且发现“使用计数”也是零。 所以它删除了“counter”对象,并删除它。 删除者仍在运行。

当然会有不同的方法来保证“反”对象的存在,但我认为增加“弱数”是一个非常优雅和直观的解决scheme。 “弱计数”成为“计数器”对象的参考计数。 而且由于shared_ptr引用了counter对象,所以也必须增加“weak count”。

一个更直观的解决scheme可能是增加每个shared_ptr的“弱计数”,因为每个shared_ptr持有对“counter”对象的引用。

为所有shared_ptr实例添加一个只是一个优化(复制/分配shared_ptr实例时保存一个primefaces增量/减量)。

基本上,“weak_ptr”是一个普通的“T *”指针,可以让你在代码中稍后恢复一个强引用,即“shared_ptr”。

就像一个普通的T *,weak_ptr不做任何引用计数。 在内部,为了支持任意typesT的引用计数,STL(或其他实现这种逻辑的库)创build一个封装对象,我们称之为“Anchor”。 “锚点”仅仅是为了实现我们需要的引用计数和“计数为零,呼叫删除”行为。

在一个强大的引用中,shared_ptr实现了它的拷贝,操作符=,构造函数,析构函数和其他相关的API来更新“Anchor”的引用计数。 这就是shared_ptr如何确保你的“T”能够像使用它的人一样长存。 在“weak_ptr”中,这些相同的API只是复制实际的Anchor ptr。 他们不更新引用计数。

这就是为什么“weak_ptr”的最重要的API是“过期的”,而这个不好的名字是“锁”。 “Expired”告诉你底层对象是否还在,比如“它是否已经被删除了,因为所有强引用都超出了范围?”。 “locking”将(如果可以的话)将weak_ptr转换为强参考shared_ptr,恢复引用计数。

顺便说一句,“锁”是该API的一个可怕的名字。 你不是(只是)调用一个互斥体,而是用一个弱的参考来创build一个强有力的参考,用这个“锚”来performance。 这两个模板中最大的缺陷是它们没有实现operator->,所以要做任何事情,你必须恢复原始的“T *”。 他们主要是为了支持像“shared_ptr”这样的东西,因为原始types不支持“ – >”运算符。