█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/C++/Smart Pointers and RAII
50 minIntermediate

Smart Pointers and RAII

After this lesson, you will be able to: Apply RAII + smart pointers (unique_ptr, shared_ptr, weak_ptr) instead of raw new/delete.

If your modern C++ code has `new` or `delete`, you're probably writing a bug. RAII + smart pointers eliminate ~90% of memory errors that plague C.

Prerequisites:The STL

RAII: the C++ killer feature

Resource Acquisition Is Initialization. Tie every resource (memory, file, lock, socket) to an object whose destructor releases it. Scope exit → destructor runs → resource freed. Automatically. Even on exceptions. RAII is why C++ never needs `finally` blocks and why modern C++ is safer than C.

Smart pointers

Three flavors. unique_ptr is the default; the others are rare.

tsx
#include <memory>
// unique_ptr, sole ownership. Most common.
std::unique_ptr<User> u = std::make_unique<User>("Alex", 30);
u->birthday();
// u goes out of scope → ~User() runs → memory freed. No leak possible.
// Can't copy a unique_ptr, but can MOVE it
std::unique_ptr<User> u2 = std::move(u); // u is now nullptr
// shared_ptr, reference-counted. Multiple owners.
std::shared_ptr<Config> cfg = std::make_shared<Config>();
std::shared_ptr<Config> cfg2 = cfg; // count = 2
// last shared_ptr destroyed → memory freed
// weak_ptr, non-owning observer to a shared_ptr. Breaks cycles.
std::weak_ptr<Config> obs = cfg;
if (auto locked = obs.lock()) { // safely promote to shared_ptr if alive
locked->use();
}
// NEVER do this in modern C++:
// User* raw = new User("x", 1);
// delete raw;

When to use which

unique_ptr: ALWAYS the default. 95% of dynamic allocations want sole ownership. shared_ptr: use only when ownership genuinely shared (e.g., cached objects across threads). Has runtime cost (atomic refcount). weak_ptr: with shared_ptr to break ownership cycles (parent → child → parent). raw pointer (T*): non-owning observer. The function does NOT delete it. Like a reference but nullable.

Custom deleters for non-memory resources

RAII isn't just for memory.

tsx
#include <cstdio>
#include <memory>
// Wrap a C-style FILE* in a unique_ptr with custom deleter
auto deleter = [](FILE* f) { if (f) std::fclose(f); };
std::unique_ptr<FILE, decltype(deleter)> file(std::fopen("data.txt", "r"), deleter);
if (file) {
char buf[256];
std::fgets(buf, sizeof(buf), file.get());
// file auto-closes on scope exit, even if exception thrown
}

💡 The new/delete graveyard

Every `new` is a potential leak. Every `delete` is a potential double-free or use-after-free. Use `std::make_unique<T>(...)` and `std::make_shared<T>(...)` instead. Always. The only legitimate `new` in modern C++ is in placement-new contexts (custom allocators) or in compiler-generated code.

Common mistakes

shared_ptr cycles → memory leaks. Use weak_ptr to break. Passing raw `new T(...)` to a smart pointer (use `make_unique` / `make_shared`, exception-safe). Storing a raw pointer to a smart-pointer-owned object, then deleting it. Using shared_ptr by reflex, it's heavier than unique_ptr.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←The Standard Template Library (STL)
Back to C++
Templates and C++20 Concepts→