Skip to main content

std::shared_ptr and std::weak_ptr

intermediate30 min readLesson 109 of 204

Strong and weak counts, lock() and expiry, the shared-ownership costs, and the reference-cycle trap.

std::shared_ptr<T> keeps a control block with two counters: strong (how many shared_ptrs own the object) and weak (how many weak_ptrs watch it). The object dies when the strong count hits zero; the control block dies when both do.

#include <memory>

auto a = std::make_shared<Node>();   // strong = 1
auto b = a;                          // strong = 2
b.reset();                           // strong = 1
a.reset();                           // strong = 0 โ†’ destructor runs

std::weak_ptr<T> observes without owning. It does not keep the object alive; it can ask whether the object still exists:

std::weak_ptr<Node> w = a;
if (auto locked = w.lock()) {   // atomic upgrade to shared_ptr
    locked->use();              // object is alive during this block
} else {
    // object already gone
}

Use shared_ptr only when ownership is genuinely shared across unknown lifetimes (caches, observers, graphs). It costs an atomic counter and can hide who releases what โ€” unique_ptr stays the default.

The famous trap: two nodes holding shared_ptr to each other form a reference cycle; strong counts never reach zero; both leak. The fix is one direction becoming weak_ptr โ€” child points to parent weakly.

Now practice

shared/weak practiceAn observer event that prunes expired watchers, plus lifetime probes.2 challenges ยท ยท ~35 min