理解 Scott Meyers 的第三个例子 std::weak_ptr
Understanding of Scott Meyers' third example of std::weak_ptr
Effective Modern C++ 第 137 页的最后一个示例绘制了包含对象 A
、B
和 [=15 的数据结构的场景=] 在其中,通过 std::shared_ptr
以下列方式相互连接:
std::shared_ptr std::shared_ptr
A ─────────────────▶ B ◀───────────────── C
对我来说,这意味着 类 对象 A
和 C
是(两个不相关的 类,一般来说)必须包含一个 std::shared_ptr<classOfB>
成员。
然后假设我们需要一个从B
回到A
的指针,并列出了可用的选项:指针可以是原始的、共享的或弱的,最后一个一个被选为最佳人选。
std::shared_ptr std::shared_ptr
A ─────────────────▶ B ◀───────────────── C
▲ │
│ std::weak_ptr │
└────────────────────┘
我确实理解前两个备选方案的弱点(啊哈哈),但我也看到第三个备选方案 要求 成员 A
已经由某些人管理std::shared_ptr
,否则一个std::weak_ptr
怎么可能指向它呢?
然而书中并没有提到这个“限制”/assumption/whatever,所以事实是
- 我错了
- 我是对的,但由于某些我不明白的原因,这个假设是显而易见的
- 这个假设是显而易见的,因为
std::weak_ptr
需要 一个已经存在的 std::shared_ptr
到同一个对象,但它有点奇怪我认为示例开头甚至都没有提到。
我问这个问题是为了理解这一点。
你是对的,你的第三个要点是正确的。 std::weak_ptr
总是引用现有的 std::shared_ptr
。所以,一旦我们做出决定,A 将包含
a shared_ptr<BClass>
并且 A 的实例被管理为 shared_ptr<AClass>
,我们可以使用 weak_ptr<AClass>
作为从 B 到 A 的反向引用。
在典型的用例中,您可以有一个 D-class 来管理三个成员 shared_ptr<AClass> a;
、shared_ptr<BClass> b;
和 shared_ptr<CClass> c;
,然后是一些成员函数D-class 执行 a->SetB(b);
、c->SetB(b);
、b->SetA(a);
,SetB 成员函数使用 shared_ptr,SetA 使用 weak_ptr(或在成员函数中转换为 weak_ptr)。正如您所说的那样,如果 D 确实以任何其他方式存储对 A 的引用,例如原始指针 AClass* a;
或实例 AClass a;
,那么使用 weak_ptr 根本就不是可能。
std::shared_ptr
设计的不幸后果是共享指针管理的依赖图中不能出现循环。这意味着一旦 A 通过共享指针指向 B,B 就不能以相同的方式指向 A,因为这会导致内存泄漏(两个对象都会保持活动状态)。
std::weak_ptr
的主要目的是作为弱引用,但大多数时候,它仅用作解决此问题的方法。但是,如果您一开始不通过共享指针来管理 A 的生命周期,那么 B 无论如何都无法跟踪它,因此使用原始指针、引用(或其他一些奇异的指针)是唯一的选择。相反,如果您通过共享指针拥有 A,则 weak_ptr
是唯一的选择。
在这两种情况下,选择完全取决于您之前管理 A 的决定,这是您必须在此处执行的操作(可能通过引用 A 和 C 的对象)。
Effective Modern C++ 第 137 页的最后一个示例绘制了包含对象 A
、B
和 [=15 的数据结构的场景=] 在其中,通过 std::shared_ptr
以下列方式相互连接:
std::shared_ptr std::shared_ptr
A ─────────────────▶ B ◀───────────────── C
对我来说,这意味着 类 对象 A
和 C
是(两个不相关的 类,一般来说)必须包含一个 std::shared_ptr<classOfB>
成员。
然后假设我们需要一个从B
回到A
的指针,并列出了可用的选项:指针可以是原始的、共享的或弱的,最后一个一个被选为最佳人选。
std::shared_ptr std::shared_ptr
A ─────────────────▶ B ◀───────────────── C
▲ │
│ std::weak_ptr │
└────────────────────┘
我确实理解前两个备选方案的弱点(啊哈哈),但我也看到第三个备选方案 要求 成员 A
已经由某些人管理std::shared_ptr
,否则一个std::weak_ptr
怎么可能指向它呢?
然而书中并没有提到这个“限制”/assumption/whatever,所以事实是
- 我错了
- 我是对的,但由于某些我不明白的原因,这个假设是显而易见的
- 这个假设是显而易见的,因为
std::weak_ptr
需要 一个已经存在的std::shared_ptr
到同一个对象,但它有点奇怪我认为示例开头甚至都没有提到。
我问这个问题是为了理解这一点。
你是对的,你的第三个要点是正确的。 std::weak_ptr
总是引用现有的 std::shared_ptr
。所以,一旦我们做出决定,A 将包含
a shared_ptr<BClass>
并且 A 的实例被管理为 shared_ptr<AClass>
,我们可以使用 weak_ptr<AClass>
作为从 B 到 A 的反向引用。
在典型的用例中,您可以有一个 D-class 来管理三个成员 shared_ptr<AClass> a;
、shared_ptr<BClass> b;
和 shared_ptr<CClass> c;
,然后是一些成员函数D-class 执行 a->SetB(b);
、c->SetB(b);
、b->SetA(a);
,SetB 成员函数使用 shared_ptr,SetA 使用 weak_ptr(或在成员函数中转换为 weak_ptr)。正如您所说的那样,如果 D 确实以任何其他方式存储对 A 的引用,例如原始指针 AClass* a;
或实例 AClass a;
,那么使用 weak_ptr 根本就不是可能。
std::shared_ptr
设计的不幸后果是共享指针管理的依赖图中不能出现循环。这意味着一旦 A 通过共享指针指向 B,B 就不能以相同的方式指向 A,因为这会导致内存泄漏(两个对象都会保持活动状态)。
std::weak_ptr
的主要目的是作为弱引用,但大多数时候,它仅用作解决此问题的方法。但是,如果您一开始不通过共享指针来管理 A 的生命周期,那么 B 无论如何都无法跟踪它,因此使用原始指针、引用(或其他一些奇异的指针)是唯一的选择。相反,如果您通过共享指针拥有 A,则 weak_ptr
是唯一的选择。
在这两种情况下,选择完全取决于您之前管理 A 的决定,这是您必须在此处执行的操作(可能通过引用 A 和 C 的对象)。