weak_ptr是如何工作的
How does weak_ptr work?
我了解如何使用weak_ptr
和shared_ptr
。我理解shared_ptr
是如何工作的,通过计算其对象中的引用数。weak_ptr
是如何工作的?我试着通读boost源代码,但我对boost不够熟悉,无法理解它使用的所有东西。
谢谢。
shared_ptr
使用了一个额外的"counter"对象。"共享计数"或"控制块")来存储引用计数。(顺便说一句:"counter"对象也存储了删除器。)
每个shared_ptr
和weak_ptr
都包含一个指向实际指针的指针,以及一个指向"计数器"对象的指针。
要实现weak_ptr
, "counter"对象存储两个不同的计数器:
- "使用计数"是指向对象的
shared_ptr
实例的数量。 - "弱计数"是指指向对象的
weak_ptr
实例的数量,如果"使用计数"仍然> 0,则加1。
当"use count"为0时,指针被删除。
当"弱计数"达到零时,"计数器"helper对象被删除(这意味着"使用计数"也必须为零,见上文)。
当您尝试从weak_ptr
获取shared_ptr
时,库自动检查"使用计数",如果> 0则增加它。如果成功,你就得到了shared_ptr
。如果"use count"已经为零,则会得到一个空的shared_ptr
实例。
EDIT:现在,为什么他们在弱计数中添加1,而不是在两个计数都降为0时释放"计数器"对象?好问题。
另一种方法是在"use count"answers"weak count"都降为零时删除"counter"对象。第一个原因是:在每个平台上原子地检查两个(指针大小的)计数器是不可能的,即使有,它也比只检查一个计数器要复杂得多。
另一个原因是delete必须保持有效,直到它完成执行。由于删除器存储在"counter"对象中,这意味着"counter"对象必须保持有效。考虑一下,如果某个对象有一个shared_ptr
和一个weak_ptr
,并且它们在并发线程中同时被重置,会发生什么。让我们假设shared_ptr
首先出现。它将"使用计数"减少到零,并开始执行删除程序。现在weak_ptr
将"弱计数"减少到零,并发现"使用计数"也为零。因此它删除了"counter"对象,并删除了delete对象。当删除程序仍在运行时。
当然,有不同的方法来确保"计数器"对象保持存活,但我认为将"弱计数"增加1是一个非常优雅和直观的解决方案。"弱计数"成为"计数器"对象的引用计数。由于shared_ptr
也引用了计数器对象,它们也必须增加"弱计数"。
一个更直观的解决方案可能是增加每个shared_ptr
的"弱计数",因为每个shared_ptr
hold都是对"计数器"对象的引用。
为所有shared_ptr
实例添加一个只是一个优化(在复制/分配shared_ptr
实例时节省一个原子增量/减量)。
基本上,"weak_ptr"是一个普通的"T*"指针,它允许您恢复强引用,即:"shared_ptr",后面的代码。
就像普通的T*一样,weak_ptr不做任何引用计数。在内部,为了支持对任意类型T的引用计数,STL(或实现这种逻辑的任何其他库)创建了一个包装器对象,我们将其称为"Anchor"。"Anchor"的存在仅仅是为了实现引用计数和我们需要的"当计数为零时,调用delete"行为。
在强引用中,shared_ptr实现了它的copy、operator=、构造函数、析构函数和其他相关的api来更新"Anchor"的引用计数。这就是shared_ptr如何确保你的"T"正好在有人使用它的时候存在。在"weak_ptr"中,这些相同的api只是复制了实际的锚ptr。它们不更新引用计数。
这就是为什么"weak_ptr"最重要的api是"expired"和名字不好的"lock"。"过期"告诉你底层对象是否仍然存在。"它是否已经删除了自己,因为所有强引用都超出了范围?"Lock"将(如果可以的话)将weak_ptr转换为强引用shared_ptr,从而恢复引用计数。
顺便说一句,"锁"对这个API来说是个糟糕的名字。您不(只是)调用互斥锁,您是从弱引用创建强引用,由"锚"起作用。这两个模板最大的缺陷是它们没有实现操作符->,所以要对对象执行任何操作,必须恢复原始的"T*"。他们这样做主要是为了支持"shared_ptr"之类的东西,因为基本类型不支持"->"操作符。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?
- sdl软件渲染器不工作,工作在硬件加速的一个