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

85,308

Solution 1

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

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

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.

Share:
85,308
Violet Giraffe
Author by

Violet Giraffe

I'm from Kharkiv, Ukraine. My city is being destroyed every day. Help us defend: https://www.comebackalive.in.ua/donate PC enthusiast, C++ fan and C++ / Qt / Android software developer. Also &lt;3 Arduino. Music and car addict. Reinventing various wheels in my spare time. A custom-made square wheel is like a tailored suit, wouldn't you agree? Why do I have more rep from questions than from answers? Because you don't learn by answering; you learn by asking questions :) Ongoing personal open-source projects: Dual-panel file manager for Windows / Linux / Mac

Updated on July 08, 2022

Comments

  • Violet Giraffe
    Violet Giraffe almost 2 years

    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.