C++Smart PointersModern C++Memory ManagementRAIIReference CountingInteractive VisualizationCore Concept
Smart Pointers in Modern C++
Master C++11 smart pointers through interactive examples. Learn unique_ptr, shared_ptr, and weak_ptr with reference counting visualizations.
Best viewed on desktop for optimal interactive experience
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.
The Three Smart Pointers
std::unique_ptr
: Exclusive ownershipstd::shared_ptr
: Shared ownership with reference countingstd::weak_ptr
: Non-owning observation
Smart Pointers Deep Dive
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>();
Widget
Owned by: ptr1
ptr1
Owner
ptr2
Not created
ptr3
Not created
Step 1: Create unique_ptr
Key Takeaways
Smart Pointers Best Practices:
- • 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
Common Pitfalls:
- • 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_ptr
can 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
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_ptr
objects - 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_unique
andmake_shared
for creation - Use
unique_ptr
by default,shared_ptr
when sharing needed - Break cycles with
weak_ptr
- 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.