The final example at page 137 of Effective Modern C++ draws the scenario of a data structure with objects A, B, and C in it, connected to each other via std::shared_ptr in the following way:
std::shared_ptr std::shared_ptr
A ─────────────────▶ B ◀───────────────── C
To me, this implies that the classes which objects A and C are instance of (two unrelated classes, in general) must contain a std::shared_ptr<classOfB> member.
Then the supposition is made that we need a pointer from B back to A, and the available options are listed: the pointer can be raw, shared, or weak, and the last one is picked up as the best candidate.
std::shared_ptr std::shared_ptr
A ─────────────────▶ B ◀───────────────── C
▲ │
│ std::weak_ptr │
└────────────────────┘
I do understand the weaknesses (ahahah) of the first two alternatives, but I also see that the third alternative requires that member A be already managed by some std::shared_ptr, otherwise how can a std::weak_ptr point to it at all?
However the book does not refer to this "limitation"/assumption/whatever, so the truth is either
- I'm wrong
- I'm right but that assumption is obvious for some reason I don't understand
- The assumption is obvious for the exact reason that a
std::weak_ptrneeds an already existingstd::shared_ptrto the same object, but it's a bit strange it's not even mentioned at the beginning of the example, I think.
and I'm asking this question to understand this.
The unfortunate consequence of the design of
std::shared_ptris that no cycles can appear in the dependency graph managed by shared pointers. This means that once A points to B via a shared pointer, B cannot point the same way to A since that will lead to a memory leak (both objects will keep themselves alive).std::weak_ptrserves its primary purpose as a weak reference, but most of the times, it is used only as a fix for this issue. However, if you don't manage the lifetime of A via a shared pointer in the first place, B has no way of tracking it anyway, so using a raw pointer, a reference (or some other exotic pointer) is the only option. Conversely, if you own A via a shared pointer,weak_ptris the only option.In both cases, the choice completely depends on your prior decision of managing A, which is something you'd had to do here (possibly via an object that refers to both A and C).