RAII and Smart Pointers
Manual memory management with new and delete is error-prone. RAII (Resource Acquisition Is Initialization) is a C++ idiom that makes resource management safe by tying it to object lifetimes.
RAII: Resource Acquisition Is Initialization
The core idea: when a resource is acquired (memory, file, lock), wrap it in an object whose destructor releases the resource. When the object goes out of scope — whether by normal return, early return, or exception — the destructor runs automatically.
{
std::unique_ptr<int> p = std::make_unique<int>(42);
// Memory is automatically freed when p goes out of scope
}Smart Pointers
std::unique_ptr — Exclusive Ownership
auto p = std::make_unique<int>(42);
// p owns the memory — no other pointer can own it
// p2 = p; // ❌ compilation error — no copy
auto p2 = std::move(p); // ✅ transfers ownership
// p is now nullptrstd::shared_ptr — Shared Ownership
auto p = std::make_shared<int>(42);
auto p2 = p; // both share ownership
// Reference count is now 2
// When p2 goes out of scope, count drops to 1
// When the last owner goes out of scope, memory is freedstd::weak_ptr — Non-owning Observer
std::shared_ptr<int> shared = std::make_shared<int>(42);
std::weak_ptr<int> weak = shared; // observes but doesn't own
if (auto locked = weak.lock()) { // check if still alive
std::cout << *locked << "\n"; // safe to use
}When to Use Each
| Pointer | Use when |
|---|---|
std::unique_ptr | Only one owner. Prefer this for almost all cases. |
std::shared_ptr | Multiple owners, lifetime is unpredictable. |
std::weak_ptr | Observing a shared_ptr without extending its lifetime (avoids cycles). |
Common Pitfalls
-
Mixing
new/deletewith smart pointers — don'tnewaunique_ptr:cpp std::unique_ptr<int> p(new int(42)); // ❌ — exception safety issue auto p = std::make_unique<int>(42); // ✅ -
Circular references — two
shared_ptrs pointing at each other never get freed:cpp struct Node { std::shared_ptr<Node> next; std::weak_ptr<Node> prev; // ✅ use weak_ptr to break the cycle }; -
Returning raw pointers from
unique_ptrfunctions — always return the smart pointer, not a raw pointer.