weak_ptr 包含哪些变量?
What variables does weak_ptr hold?
我了解可用的方法以及它们是什么。请描述 weak_ptr class 的私人部分或给出一些自定义 weak_ptr 代码的示例。我无法通过 std::weak_ptr 实现来理解。
非侵入式共享指针实现通常包含指向某些动态分配的指针 "state",它计算对原始对象的引用数量。
复制共享指针时,副本得到相同的指针指向相同的"state","state"内的计数增加到表明现在有两个共享指针共享资源。
当共享指针被销毁时,它会递减 计数器以指示现在共享资源的指针减少了一个。如果这导致计数器读数为零,则资源将被销毁。
弱指针也有指向此 "state" 的指针,但它不会 增加或减少计数器。当被询问时,它将使用相同的状态构造一个共享指针,但前提是计数不为零。如果计数为零,则最后一个共享指针已经破坏了资源,我们无法再访问它。
有趣的是,您还需要这样的逻辑来控制"state" 对象的生命周期。 :) (我想这是使用第二个计数器实现的,shared_ptr
和 weak_ptr
都会递增,但不要引用我的话。)
(your data) (ref. counters)
║ ║
[resource] [state]
┆ │ │ │ │ │
┆ │ └─[shared_ptr]───┘ │ │
┆ └───[shared_ptr]─────┘ │
└┄┄┄┄┄┄┄[weak_ptr]────────┘
当然,任何特定 std::weak_ptr
实现的私有部分到底是什么样子取决于编写它的人。
顺便说一下,如果您怀疑它指向的资源可能 已经 ,那么该图显示了为什么您不应该从原始指针构造 shared_ptr
由其他地方的 shared_ptr
(s) 管理:你会得到第二个不相关的 "state" 对象,你的计数器将是错误的,你的资源可能会过早销毁(并且肯定会被销毁两次,如果存在这样的概念),造成混乱。
为了理解链接的共享弱对,您必须首先想象一个没有任何 "weak reference" 特征的纯共享 "smart pointer"。为了提高效率,想象它是一个侵入性的拥有引用计数的指针:计数器成为托管对象的一部分。
回到 "weak reference" 特性的实现:我们需要一个对象,它可以检测一个引用对象是否还活着,并绑定一个真实的(强)引用到它(原子地)。 "is still alive" 的测量需要在一直存在的引用计数上进行(直到不再需要它,当引用为零时,强或弱),因此 "weak reference" 需要能够使该计数器保持活动状态。因此 "weak reference" 是对侵入式计数数据结构的拥有(强)引用,该数据结构保持外部计数数据结构的引用计数,weak_ptr<T>
类型 T
的托管对象。
实现必须恰好在没有更多真实(强)引用(shared_ptr
)时销毁类型 T
的托管对象,因此它必须具有用于该目的的原子计数器。请注意,从技术上讲,它不一定是某种原子整数,但 atomic<int>
恰好是获得该效果的简单方法。操作是:
- 通过其他所有者的副本创建所有者(
shared_ptr
到 shared_ptr
):自动递增计数
- 所有者销毁和测试:自动递减并测试最后一个所有者(即计数为零)
- owner creation from weak reference (
weak_ptr
to shared_ptr
): 原子测试count是否非零,然后增加并指示成功,否则不修改计数并指示失败
所有这些操作都可以在原子变量上进行。它们都涉及原子 RMW(读取修改写入),这通常比简单的读取或写入要昂贵得多。但是,如果该位置在本地 L1d 缓存中可用并且不会在 CPU 之间跳动,则成本会更低。
另一个计数是针对侵入式计数的对象:弱引用的计数必须是独立的,因为即使 T
类型的对象已被销毁,它也可能不为零。
对管理数据结构的计数进行的唯一操作是递增和递减并测试,因为对于稳定对象永远无法达到零值:零表示正在被销毁的对象。
当然,通常只有一个单词可以被原子操作,每个计数器通常是一个单词,因为在某些情况下半个单词可能会溢出,但一个单词不会(因为你没有内存来创建 2 * * 31 个对象,对于 64 位机器甚至是 2 ** 63 个);所以对计数器的修改有限制。一个简单的解决方案是侵入式引用计数不会跟踪强所有者的更改,这些更改已经很好地保存在一个计数器中,不需要在另一个计数器中复制。侵入式计数器只服务于对T
的最后一个强引用和对T
(这里的weak_ptr
)的弱引用,它们也是对管理数据结构的强引用。
所以有两个原子计数器:
- 强引用计数:确定
T
何时被销毁(及其内存释放,除非分配与管理数据共享,如 make_shared
- the (weak reference plus last strong reference) count: 表示存在多少个引用,所有强引用算一个
其他变体可能是可能的,如果您放弃线程安全,您可以获得更多创意(您可以想象所有者的链接列表),但这些可能不会更有效率。
我了解可用的方法以及它们是什么。请描述 weak_ptr class 的私人部分或给出一些自定义 weak_ptr 代码的示例。我无法通过 std::weak_ptr 实现来理解。
非侵入式共享指针实现通常包含指向某些动态分配的指针 "state",它计算对原始对象的引用数量。
复制共享指针时,副本得到相同的指针指向相同的"state","state"内的计数增加到表明现在有两个共享指针共享资源。
当共享指针被销毁时,它会递减 计数器以指示现在共享资源的指针减少了一个。如果这导致计数器读数为零,则资源将被销毁。
弱指针也有指向此 "state" 的指针,但它不会 增加或减少计数器。当被询问时,它将使用相同的状态构造一个共享指针,但前提是计数不为零。如果计数为零,则最后一个共享指针已经破坏了资源,我们无法再访问它。
有趣的是,您还需要这样的逻辑来控制"state" 对象的生命周期。 :) (我想这是使用第二个计数器实现的,shared_ptr
和 weak_ptr
都会递增,但不要引用我的话。)
(your data) (ref. counters)
║ ║
[resource] [state]
┆ │ │ │ │ │
┆ │ └─[shared_ptr]───┘ │ │
┆ └───[shared_ptr]─────┘ │
└┄┄┄┄┄┄┄[weak_ptr]────────┘
当然,任何特定 std::weak_ptr
实现的私有部分到底是什么样子取决于编写它的人。
顺便说一下,如果您怀疑它指向的资源可能 已经 ,那么该图显示了为什么您不应该从原始指针构造 shared_ptr
由其他地方的 shared_ptr
(s) 管理:你会得到第二个不相关的 "state" 对象,你的计数器将是错误的,你的资源可能会过早销毁(并且肯定会被销毁两次,如果存在这样的概念),造成混乱。
为了理解链接的共享弱对,您必须首先想象一个没有任何 "weak reference" 特征的纯共享 "smart pointer"。为了提高效率,想象它是一个侵入性的拥有引用计数的指针:计数器成为托管对象的一部分。
回到 "weak reference" 特性的实现:我们需要一个对象,它可以检测一个引用对象是否还活着,并绑定一个真实的(强)引用到它(原子地)。 "is still alive" 的测量需要在一直存在的引用计数上进行(直到不再需要它,当引用为零时,强或弱),因此 "weak reference" 需要能够使该计数器保持活动状态。因此 "weak reference" 是对侵入式计数数据结构的拥有(强)引用,该数据结构保持外部计数数据结构的引用计数,weak_ptr<T>
类型 T
的托管对象。
实现必须恰好在没有更多真实(强)引用(shared_ptr
)时销毁类型 T
的托管对象,因此它必须具有用于该目的的原子计数器。请注意,从技术上讲,它不一定是某种原子整数,但 atomic<int>
恰好是获得该效果的简单方法。操作是:
- 通过其他所有者的副本创建所有者(
shared_ptr
到shared_ptr
):自动递增计数 - 所有者销毁和测试:自动递减并测试最后一个所有者(即计数为零)
- owner creation from weak reference (
weak_ptr
toshared_ptr
): 原子测试count是否非零,然后增加并指示成功,否则不修改计数并指示失败
所有这些操作都可以在原子变量上进行。它们都涉及原子 RMW(读取修改写入),这通常比简单的读取或写入要昂贵得多。但是,如果该位置在本地 L1d 缓存中可用并且不会在 CPU 之间跳动,则成本会更低。
另一个计数是针对侵入式计数的对象:弱引用的计数必须是独立的,因为即使 T
类型的对象已被销毁,它也可能不为零。
对管理数据结构的计数进行的唯一操作是递增和递减并测试,因为对于稳定对象永远无法达到零值:零表示正在被销毁的对象。
当然,通常只有一个单词可以被原子操作,每个计数器通常是一个单词,因为在某些情况下半个单词可能会溢出,但一个单词不会(因为你没有内存来创建 2 * * 31 个对象,对于 64 位机器甚至是 2 ** 63 个);所以对计数器的修改有限制。一个简单的解决方案是侵入式引用计数不会跟踪强所有者的更改,这些更改已经很好地保存在一个计数器中,不需要在另一个计数器中复制。侵入式计数器只服务于对T
的最后一个强引用和对T
(这里的weak_ptr
)的弱引用,它们也是对管理数据结构的强引用。
所以有两个原子计数器:
- 强引用计数:确定
T
何时被销毁(及其内存释放,除非分配与管理数据共享,如make_shared
- the (weak reference plus last strong reference) count: 表示存在多少个引用,所有强引用算一个
其他变体可能是可能的,如果您放弃线程安全,您可以获得更多创意(您可以想象所有者的链接列表),但这些可能不会更有效率。