I came across this post and one of the answers by @kerek SB states
std::shared_ptr<Object> p1 = std::make_shared<Object>("foo"); std::shared_ptr<Object> p2(new Object("foo"));
In your code, the second variable is just a naked pointer, not a shared pointer at all.
Now on the meat. make_shared is (in practice) more efficient, because it allocates the reference control block together with the actual object in one single dynamic allocation. By contrast, the constructor for shared_ptr that takes a naked object pointer must allocate another dynamic variable for the reference count. The trade-off is that make_shared (or its cousin allocate_shared) does not allow you to specify a custom deleter, since the allocation is performed by the allocator.
(This does not affect the construction of the object itself. From Object's perspective there is no difference between the two versions. What's more efficient is the shared pointer itself, not the managed object.)
Now I have two questions regarding this post and would appreciate it if someone could clarify this
Why is the second one not a shared pointer ? Will that not increment a reference count
How does make_shared only make one memory allocation and new makes two thus making make_shared more efficent ?
A little clarification on this would be appreciated.
In that question, the "second variable" referred to this line:
auto ptr_res2(new Object("new")); // this creates an Object*
Not this one:
std::shared_ptr<Object> p2(new Object("foo")); // this creates a shared_ptr<Object>
The best explanation for why make_shared
is more efficient with one allocation is to compare images. Here is what std_shared_ptr<Object>(new Object)
looks like:
The shared_ptr
has a Widget*
, but it's not in the same memory block as the ref counters since they were allocated separately. The Widget*
was passed in, and the ref counting block was allocated internally, which is why the Widget
is in a separate memory space.
On the other hand, here is what it looks like with one allocation:
(I'm stealing both pictures from Herb Sutter). We still need a Widget
and a ref counting block, but instead the whole memory block is grabbed in a single call to new
/ malloc
, just of sufficient size, so the Widget
and ref counting block end up contiguous in memory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With