C++ for Systems Programmers

std::weak_ptr

A std::shared_ptr keeps an object alive by counting owners — but sometimes you want to point at a shared object without being one of its owners, so that your pointer does not keep it alive and does not create a cycle. A std::weak_ptr is exactly that: a non-owning observer of an object managed by shared_ptr. It can tell you whether the object is still alive and let you safely obtain a temporary owning pointer if so, but on its own it never prevents the object from being destroyed.

Concretely, a weak_ptr refers to the same control block as the shared_ptrs but does not contribute to the strong reference count (it bumps a separate weak count that only governs when the control block itself can be freed). When you actually need to use the object, you call .lock(), which atomically checks the strong count: if the object is still alive it returns a fresh shared_ptr (briefly raising the count so the object can't vanish under you); if it has already been destroyed it returns an empty shared_ptr. You can also call .expired() to ask 'is it gone?'. This is the safe way to hold a 'maybe-still-there' link without either leaking or dereferencing a dead object.

Why it matters: the canonical use is breaking reference cycles. If a parent shared_ptr points to a child and the child also needs to refer back to its parent, making the back-pointer a weak_ptr lets the counts reach zero and the objects free correctly. weak_ptr is also the right tool for caches and observer lists that should not keep their targets alive. The honest point: a weak_ptr is not a pointer you can dereference — you must lock() it first, and you must check the result, because the object may have been destroyed between your last check and now.

std::weak_ptr<Node> w = parent; if (auto p = w.lock()) { use(*p); } else { /* parent already gone */ }

lock() returns a usable shared_ptr only if the object still lives; otherwise it returns empty, so there is no dangling dereference.

A weak_ptr does not extend lifetime, so .expired() being false now does not guarantee the object survives your next line in a multithreaded program — only the shared_ptr returned by lock() does. Always use the locked result, not a separate expired() check, when you mean to touch the object.

Also called
weak pointernon-owning observer弱指標弱參考