Sometimes a resource must be shared by multiple parts of your application. You cannot use a unique pointer here because ownership must be shared. C++ solves this using std::shared_ptr, which manages resources using reference counting.
Let's look at reference counting, the physical layout of shared pointers in RAM, and the shared_from_this trap.
Reference Counting: Collaborative Lifecycles
A std::shared_ptr tracks how many shared pointers reference the same resource. When you copy a shared pointer, the reference counter increments. When a shared pointer goes out of scope or is destroyed, the counter decrements. The moment the reference counter drops to zero, the resource is automatically deleted from the heap.
* The Shared Document Metaphor: A shared pointer is like a collaborative document with a user counter. The document stays open as long as at least one user is viewing it (the user count is greater than zero). The absolute second the last user closes the document tab (count hits zero), the document is deleted from the server.
The Physical Layout: Two Pointers in RAM
At the memory level, a std::shared_ptr is not a single pointer. It is a two pointer structure (consuming 16 bytes of stack space on 64-bit systems):
1. A raw pointer pointing to the managed object in memory.
2. A raw pointer pointing to a dynamically allocated helper structure called the Control Block.
The Control Block lives on the heap and contains:
* The strong reference count (tracks active shared pointers).
* The weak reference count (tracks active weak pointers).
* Custom deleters or allocators if provided.
Because the control block is shared by all instances, updating the reference count requires thread safe atomic operations. This adds a tiny synchronization overhead relative to raw pointers.
The Critical Trap: `enable_shared_from_this`
If a class object managed by a std::shared_ptr needs to pass a shared pointer of itself to a function, a common mistake is creating a new shared pointer using the this pointer directly. Do not do this!
Creating a new shared pointer from this allocates a second, completely independent control block. When both control blocks think their reference count has hit zero, they will both call delete on the same object, causing a double free crash.
To fix this trap, inherit from std::enable_shared_from_this<T> and call shared_from_this() to retrieve the original control block:
The Aliasing Constructor
There is an advanced shared pointer feature known as the aliasing constructor:
std::shared_ptr<U>(const std::shared_ptr<T>& parent, U* member)
This constructor creates a shared pointer that points to a specific sub object (like a member variable inside a struct) but shares the exact same control block of the parent object. As long as you hold the shared pointer to the member variable, the reference count of the entire parent object remains greater than zero, keeping the parent memory safe from deletion. This is highly useful for parsing zero copy networking streams.