Smart Pointers: Modern C++ Memory Management
Smart pointers were introduced in C++11 to provide automatic memory management while maintaining the performance characteristics of C++. They use RAII to ensure proper resource cleanup and eliminate most memory-related bugs.
Helpful background
RAII and scope-bound cleanup
Connect resource cleanup to object destruction, including exception unwinding.
The Three Smart Pointers
std::unique_ptr: Exclusive ownershipstd::shared_ptr: Shared ownership with reference countingstd::weak_ptr: Non-owning observation
Exclusive ownership - exactly one owner
// Creating unique_ptr
auto ptr = std::make_unique<Widget>(args);
// Transfer ownership
auto ptr2 = std::move(ptr); // ptr is now nullptr
// Automatic cleanup when out of scope
{
auto local = std::make_unique<Resource>();
} // Resource destroyed here
// Custom deleter
auto file = std::unique_ptr<FILE, decltype(&fclose)>(
fopen("data.txt", "r"), &fclose
);auto ptr1 = std::make_unique<Widget>();- • Use unique_ptr by default for single ownership
- • Use shared_ptr only when you need shared ownership
- • Use weak_ptr to break circular references
- • Prefer make_unique and make_shared for creation
- • Never mix raw pointers with smart pointers for the same object
- • Watch out for circular references with shared_ptr
- • Always check weak_ptr validity before use
Unique Pointer (std::unique_ptr)
Characteristics
- Exclusive ownership: Only one
unique_ptrcan own a resource - Move semantics: Ownership can be transferred but not copied
- Zero overhead: Same performance as raw pointers
- Custom deleters: Support for custom cleanup functions
Usage Examples
// Creating unique_ptr
auto ptr = std::make_unique<Widget>(args);
// Transfer ownership
auto ptr2 = std::move(ptr); // ptr becomes nullptr
// Custom deleter
auto file = std::unique_ptr<FILE, decltype(&fclose)>(
fopen("data.txt", "r"), &fclose
);
Shared Pointer (std::shared_ptr)
Characteristics
- Shared ownership: Multiple pointers can own the same resource
- Reference counting: Tracks how many pointers reference the object
- Thread-safe counting: Reference count operations are atomic
- Automatic cleanup: Object deleted when count reaches zero
Reference Counting Process
- Create
shared_ptr→ count = 1 - Copy
shared_ptr→ count increments - Destroy
shared_ptr→ count decrements - Count reaches 0 → object deleted
Circular Reference Problem
Break ownership cycles with weak_ptr
Use weak_ptr for non-owning links that break circular references, as the parent link below does. A weak pointer observes a shared object without affecting its reference count.
struct Node {
std::shared_ptr<Node> next;
std::weak_ptr<Node> parent; // Break cycle with weak_ptr
};
Weak Pointer (std::weak_ptr)
Characteristics
- Non-owning: Doesn't affect reference count
- Observer pattern: Safely observe
shared_ptrobjects - Cycle breaking: Prevents circular references
- Expiration checking: Can detect if object still exists
Usage Pattern
std::shared_ptr<Widget> shared = std::make_shared<Widget>();
std::weak_ptr<Widget> weak = shared;
if (auto locked = weak.lock()) {
// Use locked as shared_ptr
locked->doSomething();
} else {
// Object was destroyed
}
Best Practices
- Prefer
make_uniqueandmake_sharedfor creation - Use
unique_ptrby default,shared_ptrwhen sharing needed - Pass raw pointers to functions that don't affect ownership
- Return smart pointers from factory functions
- Use custom deleters for non-standard cleanup
Performance Considerations
unique_ptr: Zero overhead compared to raw pointersshared_ptr: Small overhead for reference countingweak_ptr: Minimal overhead, but requires lock() to accessmake_shared: More efficient thanshared_ptr(new T())
Smart pointers represent modern C++'s answer to memory management - providing safety without sacrificing performance.
Related concepts
Learn Resource Acquisition Is Initialization (RAII) - the cornerstone of C++ memory management. Understand automatic resource cleanup and exception safety.
Master C++ OOP concepts including inheritance, polymorphism, virtual functions, and modern object-oriented design principles with interactive examples.
Understand C++ pointers and references with step-by-step memory diagrams: addressing, dereferencing, aliasing, array arithmetic, and object lifetime.
Deep dive into C++ memory allocation — stack frame internals, heap allocator mechanics, fragmentation, performance benchmarks, custom allocators, RAII, and debugging with AddressSanitizer and Valgrind.
Master C++ templates and the Standard Template Library. Learn generic programming, template metaprogramming, and STL containers and algorithms.
Follow a C++ function from tokens to a simplified AST, then inspect exact source ranges, declaration references and types in a keyboard-accessible explorer.
