58

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.

CashCow
  • 29,087
  • 4
  • 53
  • 86
Violet Giraffe
  • 29,070
  • 38
  • 172
  • 299
  • 2
    The second has to be `std::make_shared()`. – nosid Aug 18 '13 at 17:01
  • 4
    Yes, but not in this case. Always use `make_shared`. See the following URL for more information: http://herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/ – nosid Aug 18 '13 at 17:04
  • @Deduplicator: how the hell is my question a duplicate of one asked a year later? – Violet Giraffe Jan 02 '15 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. – Deduplicator Jan 02 '15 at 17:46
  • 1
    @Deduplicator: fair enough. Although I think my title is clearer, too. – Violet Giraffe Jan 02 '15 at 19:25

3 Answers3

81

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.

bitfox
  • 2,101
  • 16
  • 16
Mike Seymour
  • 235,407
  • 25
  • 414
  • 617
  • 22
    It has a disadvantage: The memory block is kept around for as long as there are weak-pointers to the object. – Xeo Aug 18 '13 at 17:25
  • 2
    @Xeo: Thanks, I'd forgotten about that. – Mike Seymour Aug 18 '13 at 17:26
  • +1 for the weak pointer comment. nice. – bjackfly Aug 18 '13 at 17:57
  • 2
    @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 Jul 10 '14 at 07:38
  • 2
    @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 Jul 10 '14 at 07:59
  • 2
    @Xeo Why is this the case with make_shared but not the case with std::shared_ptr constructor? – Trismegistos Jul 10 '14 at 09:14
  • 2
    @Trismegistos: The block not being freed is the same for both. What's different is that `make_shared` puts the shared object _into_ that block, while normal construction from a pointer stores just that - the pointer, which can be freed as soon as the shared count hits 0. – Xeo Jul 10 '14 at 09:24
18

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.

Adri C.S.
  • 2,599
  • 4
  • 30
  • 61
  • 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`. – Violet Giraffe Aug 18 '13 at 17:09
  • That's bad yeah. Which compiler are you using? In Debian `g++ 4.7` doesn't have that problem. – Adri C.S. Aug 18 '13 at 17:11
  • 1
    @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. – Howard Hinnant Aug 18 '13 at 17:19
  • @HowardHinnant: Hm! Is it official? As in not buggy? – Violet Giraffe Aug 18 '13 at 17:20
  • Apple is officially supporting it back to 10.7, and indefinitely forward. – Howard Hinnant Aug 18 '13 at 17:21
  • @AdriC.S.: `clang` is now official compiler for Mac, and Apple doesn't update it often. – Violet Giraffe Aug 18 '13 at 17:21
  • @VioletGiraffe, have you seen [this](http://stackoverflow.com/questions/9135144/c-make-shared-not-available) post? If you can't have `make_shared` with your current compiler, maybe the solution in there might help. – Adri C.S. Aug 18 '13 at 17:24
10

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.

Jonathan Wakely
  • 153,269
  • 21
  • 303
  • 482
doc_ds
  • 191
  • 2
  • 3