As illustrated in the code here, the size of the object returned from make_shared is two pointers.
However, why doesn\'t make_shared
work like the following
In all implementations I'm aware of, shared_ptr
stores the owned pointer and the reference count in the same memory block. This is contrary to what other answers are saying. Additionally a copy of the pointer will be stored in the shared_ptr
object. N1431 describes the typical memory layout.
It is true that one can build a reference counted pointer with sizeof only one pointer. But std::shared_ptr
contains features that absolutely demand a sizeof two pointers. One of those features is this constructor:
template shared_ptr(const shared_ptr& r, T *p) noexcept;
Effects: Constructs a shared_ptr instance that stores p
and shares ownership with r.
Postconditions: get() == p && use_count() == r.use_count()
One pointer in the shared_ptr
is going to point to the control block owned by r
. This control block is going to contain the owned pointer, which does not have to be p
, and typically isn't p
. The other pointer in the shared_ptr
, the one returned by get()
, is going to be p
.
This is referred to as aliasing support and was introduced in N2351. You may note that shared_ptr
had a sizeof two pointers prior to the introduction of this feature. Prior to the introduction of this feature, one could possibly have implemented shared_ptr
with a sizeof one pointer, but no one did because it was impractical. After N2351, it became impossible.
One of the reasons it was impractical prior to N2351 was because of support for:
shared_ptr p(new A);
Here, p.get()
returns a B*
, and has generally forgotten all about the type A
. The only requirement is that A*
be convertible to B*
. B
may derive from A
using multiple inheritance. And this implies that the value of the pointer itself may change when converting from A
to B
and vice-versa. In this example, shared_ptr
needs to remember two things:
B*
when get()
is called.A*
when it is time to do so. A very nice implementation technique to accomplish this is to store the B*
in the shared_ptr
object, and the A*
within the control block with the reference count.