代码之家  ›  专栏  ›  技术社区  ›  choxsword

为什么shared\u ptr需要为弱ptr保留引用计数?

  •  10
  • choxsword  · 技术社区  · 6 年前

    引自《C++Primer》12.1.6美元:

    A. weak_ptr (表12.5)是一个智能指针,它不控制 它指向的对象。相反,弱ptr指向由管理的对象 一 shared_ptr 。将弱ptr绑定到共享ptr 不会更改 引用计数 共享\u ptr 。最后一次 共享\u ptr 指向 对象消失时,对象本身将被删除。 该对象将被删除,即使 有 weak_ptrs 指向它 因此得名 弱ptr ,它捕获 想法是 弱ptr 弱共享其对象。

    然而,我读到 article 表示:

    使用make\u shared更有效。shared\u ptr实现必须在一个控制块中维护内务管理信息,该控制块由引用给定对象的所有shared\u ptr和弱\u ptr共享。特别是,内务管理信息不仅必须包括一个参考计数,还必须包括两个参考计数:

    1. 强引用计数,用于跟踪当前使对象保持活动状态的shared\u ptr的数量。当最后一个强引用消失时,共享对象将被销毁(并可能被解除分配)。

    2. 一个“弱引用”计数来跟踪当前观察对象的弱PTR的数量。 当最后一个弱引用消失时,共享内务管理控制块将被销毁并解除分配(如果共享对象尚未解除分配,则会解除分配)。

    据我所知 共享\u ptr 创建人 make_shared 在同一个 control block 用那些参考计数。因此,直到最后一次 弱ptr 过期。

    问题:

    1. 底漆有问题吗? 因为 弱ptr 将实际影响该对象的生存期。
    2. 为什么 共享\u ptr 需要跟踪其弱裁判吗?弱ptr可以通过检查 强引用 在控制块中,所以我认为控制块不需要跟踪 弱引用
    3. 出于好奇,控制块是由什么创建的 共享\u ptr 看起来像是不是有点像:

      template<typename T>
      class control_block
      {
         T object;
         size_t strong_refs;
         size_t weak_refs;
         void incre();
         void decre();
         //other member functions...
      };
      //And in shared_ptr:
      template<typename T>
      class shared_ptr
      {
         control_block<T> block;//Is it like this?So that the object and refs are in the same block?
         //member functions...
      };
      
    4 回复  |  直到 6 年前
        1
  •  22
  •   BoBTFish    6 年前

    引用计数控制指向对象的生存期。弱计数没有,但是 控制(或参与控制)的生命周期 控制块,控制块

    如果引用计数变为 0 ,对象为 已销毁 ,但不一定 解除分配 。当弱计数变为 0 (或当参考计数变为 0 ,如果没有 weak_ptr 发生这种情况时),控制块将被销毁并释放,如果对象的存储尚未释放,则会释放该存储。

    之间的分离 正在销毁 取消分配 指向对象是一个您不需要关心的实现细节,但它是由使用 make_shared

    如果你这样做了

    shared_ptr<int> myPtr(new int{10});
    

    您为 int ,然后将其传递到 shared_ptr 构造函数,它分别为控制块分配存储。在这种情况下 内景 可以尽早解除分配:只要引用计数达到 0 ,即使数量仍然不足。

    如果你这样做了

    auto myPtr = make_shared<int>(10);
    

    然后 使\u共享 可能会在为 内景 和控制块一气呵成。这意味着 内景 在控制块的存储也可以释放之前,无法释放。的生存期 内景 当引用计数到达时结束 0 ,但在弱计数到达之前,不会释放其存储 0

    现在清楚了吗?

        2
  •  7
  •   madlers    6 年前

    weak\u ptr需要指向一些可以判断对象是否存在的东西,以便知道它是否可以转换为共享的\u ptr。因此,需要一个小对象来保存此信息。

    删除上周ptr(或共享ptr)时,需要销毁此内务管理控制块。因此,它必须同时计算shared\u ptr和week\u ptr。

    请注意,内务管理控制块与ptr指向的对象不同,因此week\u ptr不会影响对象的生存期。

    根据您希望智能指针具有的行为,有许多不同的方法来实现智能指针。如果你想知道更多,我推荐Alexandrescu的“现代C++设计”( https://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315 )

        3
  •  2
  •   MateuszL    6 年前

    weak\u ptr和shared\u ptr都指向包含控制块的内存。如果您在shared\u ptr计数器达到0时立即删除控制块(但弱计数器没有达到0),则会留下指向垃圾内存的弱\u ptr。然后,当您尝试使用weak\u ptr时,它会读取已释放的内存,并发生不好的事情(UB)。

    因此,只要任何弱ptr可以尝试读取,控制块就必须保持活动状态(分配和构造,而不是销毁或释放)。

    当共享计数器达到0时,主(指向的)对象将被销毁,并可能(希望)被释放。当两个计数器都达到0时,控制块将被销毁并释放。

        4
  •  0
  •   Poniros    5 年前

    一个好的第一步是 摧毁 取消分配 在你脑海中清楚地表达出这个概念,这也是一个更可取的步骤,这是一个你不需要关心(善意地暗示)的实施细节,这是一个强化无知的步骤。

    所以,让我们 SeriousObject 成为一名 class ,大小约为系统内存的一半,并在构建时控制鼠标,我们认为这意味着 破坏的 ,但不是 取消分配 例子 SeriousObject系列对象 在这种情况下。在这种情况下,虽然鼠标控制返回,但您仍然只有一半的内存可用。最坏的情况是,代码中某个地方有一个被遗忘的,甚至更糟的泄露, weak_ptr 存在,留给你的记忆是一个跛脚的、情绪杀手,剩下的50%用于剩下的执行。但嘿,至少没有泄露,对吧?

    承担总结职责,下面是我对你们每个问题的假设:

    1. 存在 不是真的 我敢打赌,我知道,一半的钱是作者在发布之前对文本进行了复查,另一半的钱是错误本身现在肯定已经被发现了,如果它首先存在的话。
    2. 因为在这种情况下 弱ptr s未被跟踪, shared_ptr s和控制块均已销毁,且至少有一个 弱ptr 指向 object 存在,你认为会发生什么,当 弱ptr 按照您的建议,尝试检查 强引用 在控制块中。。。到处都是偏头痛。
    3. 这一次 肯定 我不知道,我只想说:你,以及我和许多其他与编码相关的人,忘记这个微不足道的资源,这个 嗯是的。。还有这个 一方面 绝对不是没用的 另一方面,这也是一种免费的、开源的、真实的、行业级的优质知识资源。继续,兄弟们!时间到了,抓住的时候到了,对我们来说,什么是血,什么是定义,一直都是,永远都是不可侵犯的,我们生来就享有的权利,我们通过荣誉奴役的特权,以及我们超越死亡的责任!

    PS(或者更像BTW)

    我个人的困惑不在于 弱ptr 计数,但考虑到在对象生命周期的特定阶段进行此类优化的决定,我指的是 一次性分配类型优化 我的意思是选择优化 尽可能短的 ,则, 一次性发生 终身阶段,同时接受付出这样的代价,带来这样的技术和行为副作用,作为交换,真正毫不费力地将一把山羊粪便作为他们劳动的果实。Pff公司