5

Effective Modern C++第 137 页的最后一个示例描绘了一个数据结构的场景,其中包含对象A、对象B和对象,C它们通过std::shared_ptr以下方式相互连接:

   std::shared_ptr       std::shared_ptr
A ─────────────────▶ B ◀───────────────── C

对我来说,这意味着对象和实例的类(通常是两个不相关的类)必须包含一个成员ACstd::shared_ptr<classOfB>

然后假设我们需要一个从Bback 到的指针A,并列出了可用的选项:指针可以是原始的、共享的或弱的,最后一个被选为最佳候选者。

   std::shared_ptr       std::shared_ptr
A ─────────────────▶ B ◀───────────────── C
▲                    │
│    std::weak_ptr   │
└────────────────────┘

我确实理解前两种选择的弱点(啊哈),但我也看到第三种选择要求该成员A已经由 some 管理std::shared_ptr,否则怎么能std::weak_ptr指出它呢?

然而,这本书并没有提到这个“限制”/假设/无论如何,所以事实是

  • 我错了
  • 我是对的,但出于某种我不明白的原因,这个假设很明显
  • std::weak_ptr 由于 a需要一个已经存在于同一个对象的确切原因,这个假设是显而易见的std::shared_ptr,但我认为它在示例开头甚至没有提到它有点奇怪。

我问这个问题是为了理解这一点。

4

2 回答 2

4

你是对的,你的第三个要点是正确的。Astd::weak_ptr总是指现有的std::shared_ptr. 因此,一旦我们决定 A 将包含 ashared_ptr<BClass>并且 A 的实例被管理为shared_ptr<AClass>'s,我们就可以使用 aweak_ptr<AClass>作为从 B 到 A 的反向引用。

在一个典型的用例中,你可以有一个 D 类管理三个成员shared_ptr<AClass> a;,shared_ptr<BClass> b;shared_ptr<CClass> c;, 然后 D 类中的一些成员函数a->SetB(b);, c->SetB(b);, b->SetA(a);, 使用 shared_ptr 的 SetB 成员函数和使用 weak_ptr 的 SetA (或转换为 weak_ptr在成员函数内)。正如您所说的那样,如果 D 确实以任何其他方式存储了对 A 的引用,例如原始指针AClass* a;或实例AClass a;,那么使用 weak_ptr 根本不可能。

于 2020-11-19T10:17:32.003 回答
3

设计的不幸结果std::shared_ptr是,共享指针管理的依赖图中不会出现任何循环。这意味着一旦 A 通过共享指针指向 B,B 就不能以相同的方式指向 A,因为这将导致内存泄漏(两个对象都将保持活动状态)。

std::weak_ptr其主要目的是作为弱参考,但大多数情况下,它仅用作此问题的修复。但是,如果您首先不通过共享指针管理 A 的生命周期,那么 B 无论如何都无法跟踪它,因此使用原始指针、引用(或其他一些外来指针)是唯一的选择。相反,如果您通过共享指针拥有 A,weak_ptr则这是唯一的选择。

在这两种情况下,选择完全取决于您之前管理 A 的决定,这是您必须在这里做的事情(可能通过同时引用 A 和 C 的对象)。

于 2020-11-19T19:45:37.090 回答