std::shared_ptr initialization: make_shared<Foo>() vs shared_ptr<T>(new Foo)

C++C++11Shared PtrSmart Pointers

C++ Problem Overview


What's the difference between:

std::shared_ptr<int> p = std::shared_ptr<int>( new int );

and

std::shared_ptr<int> p = std::make_shared< int >();

?

Which one should I prefer and why?

P. S. Pretty sure this must have been answered already, but I can't find a similar question.

C++ Solutions


Solution 1 - C++

Both examples are rather more verbose than necessary:

std::shared_ptr<int> p(new int);  // or '=shared_ptr<int>(new int)' if you insist
auto p = std::make_shared<int>(); // or 'std::shared_ptr<int> p' if you insist

> What's the difference?

The main difference is that the first requires two memory allocations: one for the managed object (new int), and one for the reference count. make_shared should allocate a single block of memory, and create both in that.

> Which one should I prefer and why?

You should usually use make_shared as it's more efficient. As noted in another answer, it also avoids any possibility of a memory leak, since you never have a raw pointer to the managed object.

However, as noted in the comments, it has a potential disadvantage that the memory won't be released when the object is destroyed, if there are still weak pointers preventing the shared count from being deleted.


EDIT 2020/03/06:

Further recommendations come also from the official Microsoft documentation with associated examples. Keep the focus on the Example 1 snippet:

> Whenever possible, use the make_shared function to create a shared_ptr > when the memory resource is created for the first time. make_shared is > exception-safe. It uses the same call to allocate the memory for the > control block and the resource, which reduces the construction > overhead. If you don't use make_shared, then you have to use an > explicit new expression to create the object before you pass it to the > shared_ptr constructor. The following example shows various ways to > declare and initialize a shared_ptr together with a new object.

Solution 2 - C++

From en.cppreference.com

In contrast, the declaration std::shared_ptr<T> p(new T(Args...)) performs at least two memory allocations, which may incur unnecessary overhead.

Moreover, f(shared_ptr<int>(new int(42)), g()) can lead to memory leak if g throws an exception. This problem doesn't exist if make_shared is used.

So I would recommend the make_shared approach if possible.

Solution 3 - C++

Be aware that make_shared limits you to using the default allocation/deallocation functions so if you want to have more control, make_shared is not an option. In other words, something like

std::shared_ptr<uint8_t>(p, [](uint8_t *p){ /*user code */}); 

is impossible using make_shared. One could use allocate_shared instead, but only the allocator can be specified, not a deleter. Sometimes one need to control allocation and deletion of the wrapped class.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionViolet GiraffeView Question on Stackoverflow
Solution 1 - C++Mike SeymourView Answer on Stackoverflow
Solution 2 - C++Adri C.S.View Answer on Stackoverflow
Solution 3 - C++doc_dsView Answer on Stackoverflow