75

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.

5
  • 2
    The second has to be std::make_shared<int>(). Commented Aug 18, 2013 at 17:01
  • 5
    Yes, but not in this case. Always use make_shared. See the following URL for more information: herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers Commented Aug 18, 2013 at 17:04
  • @Deduplicator: how the hell is my question a duplicate of one asked a year later? Commented Jan 2, 2015 at 17:06
  • @VioletGiraffe: I think the other one is a slightly better, and they cover the same territory. Age only comes in as a tie-breaker (even though it's unfortunately too prominent in the explanatory text), and older questions have a higher chance to be well-polished. Commented Jan 2, 2015 at 17:46
  • 1
    @Deduplicator: fair enough. Although I think my title is clearer, too. Commented Jan 2, 2015 at 19:25

3 Answers 3

103

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.

Sign up to request clarification or add additional context in comments.

7 Comments

It has a disadvantage: The memory block is kept around for as long as there are weak-pointers to the object.
@Xeo: Thanks, I'd forgotten about that.
@Xeo Can you elaborate a little bit on weak ptr issue? Weak pointers were created not to hold memory so why it is the case in this situation?
@Trismegistos: Because the shared block, that holds the data and counters for weak and shared pointers, can only be released after the last associated weak_ptr has been destroyed - otherwise, how would the weak_ptr know that its parent is gone?
@Xeo Why is this the case with make_shared but not the case with std::shared_ptr constructor?
|
27

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.

7 Comments

Thanks. Too bad there are problems with shared_ptr and make_shared on Mac (they're still in tr1 namespace so I have to define macros to write portable code using shared pointers). I mean, additional macro is required to use make_shared.
That's bad yeah. Which compiler are you using? In Debian g++ 4.7 doesn't have that problem.
@VioletGiraffe: On the Mac you can specify -stdlib=libc++ (in Xcode find "C++ Standard Library" in build settings and choose "libc++"). This will get you a C++11 std::lib.
@HowardHinnant: Hm! Is it official? As in not buggy?
Apple is officially supporting it back to 10.7, and indefinitely forward.
|
13

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.