Skip to content

Module 11 — Summary

The essentials

  • RAII ties release to scope exit — acquire in a constructor, release in a destructor. It is the only mechanism guaranteed to run on every way out of a scope, including the one taken while an exception is propagating, and it therefore applies to files, locks, sockets and connections exactly as it applies to memory.
  • A raw pointer says nothing about ownership. Smart pointers put the answer in the type, where the compiler enforces it and where every reader can see it without reading a body.
  • unique_ptr is the default for exclusive ownership: move-only, effectively free (sizeof equals a raw pointer), and its deleted copy is a feature — a second owner cannot exist. Create one with make_unique, never with new.
  • shared_ptr is for ownership that genuinely cannot be attributed to one owner. It costs a second pointer and a control block, and its reference count protects the count, not the object. "Thread-safe count" does not mean "thread-safe object".
  • weak_ptr observes without owning. lock() gives you a temporary owner if the object still exists; expired() answers a question you should not then act on. Check-then-use is a race; lock-then-use is not.
  • Cycles leak, silently. Two shared_ptrs that own each other can never reach a zero count, so no destructor runs. A leak checker calls this memory still reachable, which is why cycles survive review and testing: nothing is invalid, so nothing is reported.
  • One object, one control block. shared_ptr<T>(raw) creates a second control block and therefore a second delete. make_shared, enable_shared_from_this and a factory that returns shared_ptr are how you guarantee one.
  • Borrow, do not own. Take const T&, T& or T* when the callee is not taking ownership; take an owning pointer by value only to transfer. A shared_ptr parameter on a function that stores nothing is a false promise with a real cost.
  • Polymorphic containers need owning pointers and a virtual destructor — Modules 7 and 11 meeting. A std::vector<std::unique_ptr<Base>> holds several kinds and cleans them all up with no destructor written for the container.
  • Ownership bugs are mostly legal, so the technique is measurement: counters on acquisition and release, an instance counter on the type while you develop it, and a sanitizer for the subset of bugs that are actually invalid.

The one-sentence version

Put every resource inside an object whose destructor releases it, say who owns this in the type rather than in a comment, and then cleanup is not something you remember — it is something the compiler and the language guarantee.

Terms you must now be able to define

RAII · automatic cleanup · scope / stack unwinding · resource · ownership · borrow · unique_ptr · make_unique · shared_ptr · make_shared · control block · reference count · weak_ptr · lock() / expired() · reference cycle · still reachable · enable_shared_from_this · custom deleter · noexcept destructor · Rule of Zero achieved

All of them are defined in the glossary under this module.

Before you move on

  • [ ] All core exercises attempted, with the results checked — including the two counter runs
  • [ ] The lab builds with no warnings, and its throwing run is captured alongside the normal one
  • [ ] The cycle was reproduced on purpose, with the destructor silence recorded
  • [ ] Quiz score ≥ 80%, and every miss explained
  • [ ] At least one challenge problem attempted, with the trade-off written down
  • [ ] Skills checklist ticked, with the evidence for each item
  • [ ] I can read any declaration and say who owns what — and where the type does not say it, I know that it does not

Where this goes next

Module 12 — Templates multiplies every decision on this page. A template written for one record kind must be correct for another, which means it must be correct for any ownership model those kinds use: whether they can be copied, whether their moves are noexcept, whether they own resources at all. Lab 12 asks for one Repository<T> serving two kinds of record, and the first question it raises is whether your types can be copied — which is exactly what Modules 10 and 11 settled.

Module 13 — Exception Handling is where this module's property becomes essential rather than tidy. Exception safety is defined in terms of what happens during unwinding, and the only thing guaranteed to happen during unwinding is a destructor. If release is not tied to a destructor, a failure path cannot be made correct at all.

Further reading

  • Effective Modern C++, Scott Meyers — the items on unique_ptr, shared_ptr, weak_ptr and enable_shared_from_this are the definitive treatment of this module, and the source of several of its mistakes.
  • A Tour of C++ (3rd ed.), Bjarne Stroustrup — resource management presented as the language's central idea rather than as a library detail.
  • The C++ Core Guidelines, sections on resource management and ownership — the rules this module teaches, stated as rules, with the reasoning attached.

See Further Reading for the full list, with what each source is good for and when to reach for it.