# weak_ptr **`std::weak_ptr`** is a non-owning observer of an object managed by [[shared-ptr|shared_ptr]]: it can check whether the object still exists and temporarily obtain a `shared_ptr` to it, but holding a `weak_ptr` alone never keeps the object alive. It exists specifically to break the reference cycles that plain `shared_ptr` can't resolve on its own. ## The cycle problem Two objects that hold `shared_ptr`s to each other keep each other's strong reference count above zero forever, even if nothing else in the program refers to either of them. Neither destructor ever runs, and the memory leaks silently, no crash, no warning, just objects that are unreachable from anywhere else in the program but never freed. ```cpp struct Node { std::shared_ptr next; // if two Nodes point at each other, }; // neither's refcount ever reaches zero auto a = std::make_shared(); auto b = std::make_shared(); a->next = b; b->next = a; // cycle: a and b keep each other alive forever ``` The standard place this shows up is a parent/child or observer relationship: a parent holding `shared_ptr` and each child holding `shared_ptr` back creates exactly this cycle. The fix is for one direction of the relationship, typically the "back" reference (child to parent, observer to subject), to be a `weak_ptr` instead. ```cpp struct Node { std::weak_ptr parent; // back-reference, doesn't keep parent alive std::shared_ptr child; // forward-reference, owns the child }; ``` ## Using a weak_ptr Since the observed object might have already been destroyed, a `weak_ptr` can't be dereferenced directly. `lock()` atomically checks whether the object is still alive and, if so, returns a `shared_ptr` to it (which itself keeps the object alive for as long as that `shared_ptr` is held); if the object is gone, `lock()` returns a null `shared_ptr`. ```cpp std::weak_ptr weak_parent = child->parent; if (std::shared_ptr parent = weak_parent.lock()) { parent->doThing(); // safe: parent is guaranteed alive for this scope } else { // parent has already been destroyed } ``` This lock-then-check pattern is the whole reason `weak_ptr` exists as its own type rather than just a raw pointer: a raw pointer gives no way to ask "is the pointee still alive" safely, since dereferencing a dangling raw pointer is undefined behavior, while `weak_ptr::lock()` turns that question into a defined, atomic operation. ## Links - https://en.cppreference.com/w/cpp/memory/weak_ptr.html