C++ RAII, Ownership, and Smart Pointers
Tie resource lifetime to object lifetime, prefer automatic storage and value members, and use unique_ptr or shared_ptr only when ownership requires them.
Before this lesson
Explain deterministic destruction and scope cleanup
Prefer value members and unique ownership
Distinguish unique_ptr shared_ptr and weak_ptr roles
The short answer
RAII acquires a resource in an object and releases it in the destructor, so cleanup follows scope even during early returns or exceptions. Prefer values and unique ownership; shared ownership is a specific lifetime model, not a default.
Resources need one lifetime owner
Memory, file handles, locks, and sockets must be released exactly once after their last valid use. Manual cleanup placed at the bottom of a function fails when an earlier return, exception, or new branch skips it. Ownership answers who is responsible for release.
The best owner is often an ordinary value. A std::vector owns its elements, a std::string owns its character storage, and a file stream owns an open file handle. Dynamic allocation is not required merely because C++ permits it.
| Need | Preferred representation | Reason |
|---|---|---|
| Local object | Direct value | Automatic lifetime and no allocation |
| Resizable sequence | std::vector<T> | Owns elements and storage |
| One dynamic owner | std::unique_ptr<T> | Move-only ownership |
| Genuinely shared lifetime | std::shared_ptr<T> | Reference-counted ownership |
| Non-owning shared observation | std::weak_ptr<T> | Does not prolong lifetime |
RAII makes cleanup structural
Resource Acquisition Is Initialization means a successfully constructed object owns a valid resource and its destructor releases that resource. Scope and object lifetime then control cleanup on normal exits and exceptional exits.
This is why standard containers and streams are central to modern C++. Their destructors encode cleanup once. Application code composes those owners rather than repeating new, delete, open, close, lock, and unlock on every path.
#include <fstream>
#include <string>
void save_message(const std::string& message)
{
std::ofstream output{"message.txt"};
if (!output) return;
output << message << '\n';
} // output closes here on every exit pathUnique ownership is the default dynamic choice
std::unique_ptr<T> owns one dynamically allocated object. It cannot be copied, because two unique owners would contradict the contract. It can be moved, making ownership transfer explicit. std::make_unique creates the object and owner together.
Use unique ownership for runtime polymorphic objects, optional heavy objects, or lifetimes that must outlive one scope without being shared. Before using it, ask whether a direct member, optional value, or vector already models the need.
Quick knowledge check
Answer before you reveal.
01Why does RAII work during an exception?
Stack unwinding destroys fully constructed local objects, so their destructors release owned resources.
02When should shared_ptr be the default?
It should not be the default. Use it only when several owners genuinely share and extend one object's lifetime.
Exercise
Practice challenge
Replace a raw new and delete pair with std::unique_ptr, then move ownership into a function that consumes the object. Verify the old owner is empty.
Requirements
- No explicit delete remains
- Ownership transfer uses std::move visibly
- The object is destroyed exactly once
Optional extension: Avoid dynamic allocation entirely by storing the object as a value.
Open in C++ compilerLesson checkpoint
One small step locks it in
Mark this lesson complete, then keep the momentum going.
Clear up the details
Frequently asked questions
Does unique_ptr always allocate memory?
It owns a dynamically allocated object or custom resource; prefer a direct value when dynamic lifetime or polymorphism is unnecessary.
Why use make_unique?
It constructs the object and unique pointer together, reducing explicit allocation syntax and improving exception safety.
What problem does weak_ptr solve?
It observes an object managed by shared_ptr without adding ownership, helping break ownership cycles.