【问题标题】:Why shared_ptr's reference counting object needs to keep track of the number of weak_ptrs pointing to the object too?为什么 shared_ptr 的引用计数对象也需要跟踪指向该对象的 weak_ptr 的数量?
【发布时间】:2017-12-25 06:42:18
【问题描述】:

嗨,我正在阅读 this document 和其他一些关于 C++ 的 shared_ptr 的文档,它们似乎都表明除了指向分配对象的 shared_ptr 的数量之外,引用计数对象还必须跟踪有多少weak_ptr 指针也指向该对象。我的问题是为什么?据我了解,weak_ptr 是非拥有的,因此如果指向该对象的shared_ptr 计数达到零,则可以删除该对象。这就是为什么有时我们需要使用expired 来检查weak_ptr 指向的对象的可用性。您能解释一下需要跟踪weak_ptrs 数量的原因吗?

为什么我们在这里需要弱计数?

【问题讨论】:

  • 我相信这是因为否则,weak_ptr 将无法知道它是否已过期。您必须保持内存块处于活动状态,以便 weak_ptrs 知道指针已过期,但您还想在所有 weak_ptrs 消失后删除内存
  • @Justin 我想“你不能只测试 wp1 指向管理器对象的指针是否为空”然后我意识到“啊,你当然不能这样做,否则你解决了删除一个ptr 两次将使您的程序问题出现段错误。”
  • 基本上,唯一的其他解决方案是保留所有已存储weak_ptrs 的列表。然后,当共享计数变为 0 时,您通知每个 weak_ptr 内存已被破坏。这会降低效率,尤其是在使用的内存方面。
  • 作为旁注,您的图形具有误导性,因为指向托管对象的指针存储在每个 shared_ptr/weak_ptr 中。删除器内可能有另一个指针(在控制块又名管理器对象内)。这允许不同的指针实例具有相同的所有权关系但不同的指针

标签: c++ c++11 shared-ptr weak-ptr


【解决方案1】:

std::weak_ptr 引用控制块以了解对象是否仍然存在,如果存在,则在需要时向其提供std::shared_ptr。因此,只要std::weak_ptrstd::shared_ptr 存在,控制块就必须存在。您需要跟踪 std::weak_ptr 的实例数才能知道最后一个实例何时被销毁,就像 std::shared_ptr 一样。

【讨论】:

  • 对,如果不是这样,控制块将需要包含有关所有 weak_ptr 实例的信息,以便它们可以被清空(以线程安全的方式,不少于)到期。让weak_ptrlock() 执行轮询要容易得多。
【解决方案2】:

shared_ptr 引用计数是对象所有者的计数。 weak_ptr 引用计数是引用计数控制块的所有者的计数。

【讨论】:

  • 那么,您声称一个新的共享指针将两个值都加 1?
  • @Yakk:是的,但是好的实现会让 shared_ptrs 的群体表现得像一个weak_ptr。
  • @Yakk 增加两个整数是有问题的 WRT 原子性。
  • @curious 它不需要原子性。
【解决方案3】:

添加到 François Andrieux 的答案:

这是一个非常重要的副作用。

如果你使用 std::make_shared 的实现,它使用 WKWYL 优化(我们知道你住在哪里)将控制块和实际对象一起分配为一个连续的分配,内存将不会被释放,直到所有 weak_ptr对象也超出了范围。

(我的账号很少使用,所以无法添加cmets,因为没有足够的声望点,所以添加作为答案而不是评论)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-07
    • 2016-03-06
    • 2010-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-06
    • 1970-01-01
    相关资源
    最近更新 更多