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
std::weak_ptr
needs an already existing std::shared_ptr
to 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_ptr
is 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_ptr
serves 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_ptr
is 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).