weak_ptr如何工作?

Oli*_*eng 57 c++ boost weak-references tr1 weak-ptr

我理解如何使用weak_ptrshared_ptr.我shared_ptr通过计算其对象中的引用数来理解它是如何工作的.weak_ptr工作怎么样?我尝试阅读boost源代码,并且我不熟悉boost以了解它使用的所有内容.

谢谢.

Pau*_*oke 97

shared_ptr使用额外的"计数器"对象(又名"共享计数"或"控制块")来存储引用计数.(顺便说一下:"计数器"对象也存储删除器.)

每个shared_ptrweak_ptr包含指向实际指针的指针,以及指向"计数器"对象的第二个指针.

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

  • "使用计数"是shared_ptr指向对象的实例数.
  • "弱计数"是weak_ptr指向对象的实例数,如果"使用计数"仍然> 0,则加1.

当"使用次数"达到零时,删除指针.

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

当您尝试shared_ptr从a 获取a 时weak_ptr,库会原子地检查"使用计数",如果它> 0则递增它.如果成功,你得到你的shared_ptr.如果"使用次数"已经为零,则会获得一个空shared_ptr实例.


编辑:现在,为什么他们将一个加到弱计数而不是只是在两个计数都降到零时释放"计数器"对象?好问题.

另一种方法是在"使用计数"和"弱计数"都降为零时删除"计数器"对象.这是第一个原因:在每个平台上都不可能原子地检查两个(指针大小的)计数器,即使它在哪里,它也比仅检查一个计数器更复杂.

另一个原因是删除器必须保持有效,直到它完成执行.由于删除器存储在"计数器"对象中,这意味着"计数器"对象必须保持有效.考虑如果某个对象有一个shared_ptr和一个会发生什么weak_ptr,并且它们在并发线程中同时重置.让我们说shared_ptr先到先得.它将"使用次数"减少为零,并开始执行删除.现在将weak_ptr"弱计数"减少到零,并发现"使用计数"也为零.因此它删除了"计数器"对象,并删除了删除器.虽然删除器仍在运行.

当然会有不同的方法来确保"反"对象保持活力,但我认为将"弱计数"增加一个是一个非常优雅和直观的解决方案."弱计数"成为"计数器"对象的引用计数.并且由于shared_ptrs也引用了计数器对象,它们也必须增加"弱计数".

一个可能更直观的解决方案是增加每个单独的"弱计数" shared_ptr,因为每个单独的shared_ptr保持是对"计数器"对象的引用.

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

  • 无论如何,他们必须触摸"计数器"对象来更新"使用次数".但是,更新"弱计数"也需要双宽度CAS(在许多平台上不可用)或第二个CAS指令(这是非常昂贵的)."一劳永逸"的解决方案只需要每个指针一个额外的CAS,这是在删除指针之后.(初始化不需要原子指令,因为那时没有其他线程访问"计数器"对象). (3认同)