c++ - std::shared_ptr 内部结构,弱计数超过预期

标签 c++ stl shared-ptr

合一episode (35:00) 高级 STL 系列,Stephan T Lavavej 展示了 _Weaks,其值为 0 的计数器决定何时删除 _Ref_count 结构,等于存活的数量weak_ptr,如果存在 shared_ptr 则加 1。他解释说这是必要的,因为线程安全:如果 _Weaks 仅等于 weak_ptr 的数量,那么当最后一个 weak_ptr 超出范围时它还需要检查 _Uses,即事件 shared_ptr 的计数器,以检查是否可以删除 _Ref_count。由于缺乏原子性,这是 Not Acceptable 。

假设 _Uses = 活跃的 shared_ptr 数量,_Weaks = 活跃的 weak_ptr 数量,想象一下我们有以下场景:

  • (_Uses = 0, _Weaks = 1):最后一个 weak_ptr 超出范围, 递减 _Weaks

  • (_Uses = 0, _Weaks = 0):如果_Uses等于0 , 删除_Ref_count结构

在多线程应用程序中,什么会出错,这迫使我们使用 _Weak = number of alive weak_ptr + (number of shared_ptr ? 1 : 0) 实现?

最佳答案

想象一下以下场景。线程A持有一个shared_ptr,线程B持有一个对应的weak_ptr。因此,在您的实现中,我们有 _Uses == 1_Weaks == 1

智能指针析构函数有两种可能的实现方式,但都存在问题。

实现方式一:自减,然后校验

Bweak_ptr 被销毁。递减 _Weaks。我们有 _Uses == 1_Weaks == 0B 准备检查 _Uses,但是......

上下文切换。

Ashared_ptr 被销毁。递减 _Uses。我们有 _Uses == 0_Weaks == 0。开始销毁 _Ref_count

上下文切换。

B 现在开始检查 _Uses。为 0。开始销毁 _Ref_count

两个线程现在都在销毁_Ref_count。不好。

实现方式二:检查,然后自减

Bweak_ptr 被销毁。检查 _Uses。它是 1,不会发生破坏。 B 准备减少 _Weaks,但是......

上下文切换。

Ashared_ptr 被销毁。检查 _Weaks。它是 1,不会发生破坏。递减 _Uses。我们有 _Uses == 0_Weaks == 1。完成。

上下文切换。

B 现在循环递减 _Weaks。我们有 _Uses == 0_Weaks == 0。无事可做。

我们泄露了 _Ref_count。不好。

关于c++ - std::shared_ptr 内部结构,弱计数超过预期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43297517/

相关文章:

c++ - 有没有办法使用 C++ 堆栈容器设置堆栈大小?

java - 如何捕获本地 HTTP 流量

c++ - 如何消除并行 std::transform_reduce() 的中间容器?

c++ - 如何向集合中插入一个新值并同时删除另一个值?

c++ - 关于智能指针及其不可避免的非决定论的问题

c++ - 使用从 unique_ptr 到基类的 shared_ptr 时,enable_shared_from_this 未初始化。为什么?

c++ - 没有匹配函数调用 `std::basic_ofstream<char, std::char_traits<char>>::basic_ofstream(std::string&)'

C++:来自 Stroustrup 示例的运算符优先级

c++ - 错误:“std::copy”之间的重载歧义

c++ - shared_ptr 的控制 block 中的虚函数是什么?