【问题标题】:Where is the reference count of an object typically stored?对象的引用计数通常存储在哪里?
【发布时间】:2019-06-20 19:18:05
【问题描述】:

如果我们有一些可以接受任意对象并提供引用计数指针的智能指针类,我们如何实际存储计算引用的整数?引用计数必须在指向同一对象的智能指针类的所有实例之间共享。

我想到的一个解决方案是将引用计数存储在我们指向的对象中,但这对于通用解决方案来说并不是很好,因为每个对象都必须自己提供引用计数或从某些对象继承提供它的对象。

【问题讨论】:

  • shared_ptr<T> 不需要真正具有T*。它可以有一个reference_count_block_with<T>*,它包含一个引用计数一个T
  • 为什么不用智能指针类本身呢? stackoverflow.com/questions/9200664/…

标签: c++ smart-pointers


【解决方案1】:

它“通常存储”在对象设计所需的任何位置。侵入式智能指针需要与它们一起使用的T 来为引用计数提供存储。这就是使它们“侵入性”的原因;他们侵入了物体。

您概述的设计指定“可以采用任意对象”。因此,侵入式设计是不可能的。

由于智能指针的许多实例都必须访问同一个引用计数对象,因此该引用计数必须独立于任何一个实例。而且由于它还必须独立于T,因此它必须是一个生命周期独立于T 和任何引用它的智能指针实例的对象。

因此,智能指针在声明对T 的所有权后,还必须创建引用计数对象来管理它。通常,这是通过堆分配这样的对象来完成的。智能指针的副本也会获得指向引用计数的指针。

这也是为什么让两个不同的std::shared_ptr 构造函数声明对同一个T* 的所有权是非法的。您可以从已经拥有T*shared_ptr 复制,但您不能直接将T* 本身传递给构造函数。因为T 无法访问引用计数,shared_ptr 的构造函数不会知道其他人拥有它,所以它会创建第二个引用计数块。

【讨论】:

  • “拥有两个不同的 std::shared_ptr 是非法的”,这是通过静态分析强制/强制执行的吗?
  • @AvinKavish:它与取消引用空指针差不多。
【解决方案2】:

std::shared_ptr 使用的一般解决方案是分配一个单独的控制块,它保存引用计数(以及其他内容,例如:析构函数、weak_ptr 计数)。

(如果使用std::make_shared,控制块和对象可以生活在同一个分配中)

您在第二段中描述的东西也存在,例如:在Boost中称为intrusive_ptr

【讨论】:

    【解决方案3】:

    有许多存储引用计数的策略,具体取决于您希望支持的操作。

    这里的其他答案概述了一个选项,即在托管内存旁边分配一个辅助控制块,并使所有智能指针指向该辅助块。这使得快速确定准确的引用计数变得容易,但需要为每个智能指针进行额外分配,这可能会减慢速度,如果内存不足,可能会失败。 (当控制块不与对象本身连续存储时,查找控制块的缓存友好性也存在问题)。

    另一个选项是引用链接,其中没有明确的引用计数。相反,您通过所有智能指针将一个循环的双向链表连接起来。当向对象添加一个新的智能指针时,该智能指针被拼接到链表中,当移除一个智能指针时,该智能指针被拼接到链表之外。这消除了对辅助分配的需要(除非,比如说,您需要一个自定义删除器)并提高了局部性,但使得确定准确的引用计数变得昂贵。实际需要准确的引用计数并不常见,因此这种权衡通常是合理的。

    【讨论】:

    • 在这种情况下究竟如何获得计数?
    • 由于所有内容都连接在一个循环列表中,因此您基本上只需遍历该链接列表,直到您最终回到起点,并计算您一路走来的步数。
    • @AvinKavish:还应该注意的是,您几乎从不真正想要计数。您可能最想问的是它是否是唯一持有所有权的指针。
    猜你喜欢
    • 1970-01-01
    • 2015-07-05
    • 2021-03-17
    • 2012-02-24
    • 1970-01-01
    • 2014-02-11
    • 2014-01-14
    • 1970-01-01
    • 2017-03-19
    相关资源
    最近更新 更多