207

Does std::make_unique have any efficiency benefits like std::make_shared?

Compared to manually constructing std::unique_ptr:

std::make_unique<int>(1); // vs std::unique_ptr<int>(new int(1)); 
4
  • 1
    Does make_shared have any efficiency over just writing the long hand code? Commented Mar 21, 2014 at 23:22
  • 12
    @EdHeal It may, because make_shared can allocate both the space for the object and the space for the control block together in a single allocation. The cost of that is that the object cannot be deallocated separately from the control block, so if you use weak_ptr a lot then you may end up using more memory. Commented Mar 21, 2014 at 23:25
  • Perhaps this is a good starting point stackoverflow.com/questions/9302296/… Commented Mar 21, 2014 at 23:30
  • See this link for detailed explanation: herbsutter.com/gotw/_102 Commented May 24, 2021 at 8:42

4 Answers 4

205

The motivation behind make_unique is primarily two-fold:

  • make_unique is safe for creating temporaries, whereas with explicit use of new you have to remember the rule about not using unnamed temporaries.

    foo(make_unique<T>(), make_unique<U>()); // exception safe foo(unique_ptr<T>(new T()), unique_ptr<U>(new U())); // unsafe* 
  • The addition of make_unique finally means we can tell people to 'never' use new rather than the previous rule to "'never' use new except when you make a unique_ptr".

There's also a third reason:

  • make_unique does not require redundant type usage. unique_ptr<T>(new T()) -> make_unique<T>()

None of the reasons involve improving runtime efficiency the way using make_shared does (due to avoiding a second allocation, at the cost of potentially higher peak memory usage).

* It is expected that C++17 will include a rule change that means that this is no longer unsafe. See C++ committee papers P0400R0 and P0145R3.

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

10 Comments

It would make more sense to say std::unique_ptr and std::shared_ptr are why we can tell people to "never use new."
@TimothyShields Yeah, that's what I mean. It's just that in C++11 we have make_shared and so make_unique is the final piece that was previously missing.
Any way you could mention briefly, or link to, the reason for not using unnamed temporaries?
Actually, from stackoverflow.com/a/19472607/368896, I've got it... From that answer, consider the following function call f: f(unique_ptr<T>(new T), function_that_can_throw()); - to quote the answer: The compiler is allowed to call (in order): new T, function_that_can_throw(), unique_ptr<T>(...). Obviously if function_that_can_throw actually throws then you leak. make_unique prevents this case. So, my question is answered.
One reason I once had to use std::unique_ptr<T>(new T()) was because the constructor of T was private. Even if the call to std::make_unique was in a public factory method of class T, it didn't compile because one of the underlying methods of std::make_unique could not access the private constructor. I didn't want to make that method friend because I didn't want to rely on the implementation of std::make_unique. So the only solution was, calling new in my factory method of class T, and then wrap it in an std::unique_ptr<T>.
|
25

std::make_unique and std::make_shared are there for two reasons:

  1. So that you don't have to explicitly list the template type arguments.
  2. Additional exception safety over using std::unique_ptr or std::shared_ptr constructors. (See the Notes section here.)

It's not really about runtime efficiency. There is the bit about the control block and the T being allocated all at once, but I think that's more a bonus and less a motivation for these functions to exist.

3 Comments

They're also there for exception-safety.
@0x499602D2 And that, good addition. This page talks about that.
For future readers, C++17 does not allow for interleaving of function arguments so the argument for exception-safety doesn't hold anymore. The memory allocation for two parallel std::make_shared will ensure that at least one of them gets wrapped in the smart pointer before the other memory allocation occurs, hence no leaks.
20

A reason why you would have to use std::unique_ptr(new A()) or std::shared_ptr(new A()) directly instead of std::make_*() is being unable to access the constructor of class A outside of current scope.

2 Comments

Is there a plan to fix C++ so make_unique and make_shared can access private constructors?
@nyanpasu64 make_unique needs no fixing. You can always make it a friend of your class with a private constructor.
7

Consider function call

void function(std::unique_ptr<A>(new A()), std::unique_ptr<B>(new B())) { ... } 

Suppose that new A() succeeds, but new B() throws an exception: you catch it to resume the normal execution of your program. Unfortunately, the C++ standard does not require that object A gets destroyed and its memory deallocated: memory silently leaks and there's no way to clean it up. By wrapping A and B into std::make_unique() calls, you are sure the leak will not occur:

void function(std::make_unique<A>(), std::make_unique<B>()) { ... } 

The point here is that std::make_unique<A>() and std::make_unique<B>() return temporary objects, and cleanup of temporary objects is correctly specified in the C++ standard: their destructors will be triggered and the memory freed. So, if you can, always prefer to allocate objects using std::make_unique() and std::make_shared().

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.