ReviseAlgo Logo

Pointers and Memory Management

Smart Pointers

unique_ptr, shared_ptr, weak_ptr

Interview: Modern C++ essential

Smart Pointers

Smart pointers (C++11, <memory>) automate memory management by wrapping raw pointers and deleting them automatically when they go out of scope. They implement RAII and eliminate the most common memory bugs: leaks, double-free, and use-after-free.

std::unique_ptr

Exclusive ownership — only one unique_ptr can own an object at a time. Non-copyable, move-only. Zero overhead over raw pointer. Use as the default smart pointer for owned heap objects.

std::shared_ptr

Shared ownership via reference counting. Destructs the object when the last shared_ptr to it is destroyed. Thread-safe reference count. Overhead: atomic increment/decrement on copy, plus separate control block allocation.

std::weak_ptr

Non-owning observer of a shared_ptr. Doesn't affect reference count. Must be converted to shared_ptr (lock()) before use — returns nullptr if object was already destroyed. Breaks shared_ptr cyclic reference cycles.

Interview Corner

Q: What is a circular reference with shared_ptr and how do you fix it?

A: If A holds a shared_ptr to B and B holds a shared_ptr to A, neither's reference count reaches zero — memory leak. Fix: one of the pointers should be a weak_ptr. The object that logically "doesn't own" the other holds a weak_ptr. When it needs to use the object, it locks the weak_ptr to get a temporary shared_ptr.

Q: Why prefer make_unique/make_shared over direct new?

A: (1) Exception safety: f(shared_ptr(new T), g()) — if g() throws after new but before shared_ptr construction, memory leaks. make_shared eliminates this. (2) make_shared performs a single allocation for both the object and control block (better cache locality, one fewer allocation).

Common Pitfalls

  • Creating shared_ptr from raw this: Using shared_ptr<T>(this) inside a class creates a second control block — double-free. Inherit from std::enable_shared_from_this and use shared_from_this() instead.
  • Overusing shared_ptr: Using shared_ptr everywhere adds unnecessary reference counting overhead. Default to unique_ptr; use shared_ptr only when shared ownership is genuinely needed.

Best Practices

  • Default to std::unique_ptr. Upgrade to shared_ptr only when shared ownership is explicitly required.
  • Always use std::make_unique and std::make_shared — never raw new/delete.