Differences between std::make_unique and std::unique_ptr with new
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));
The motivation behind make_unique
is primarily two-fold:
-
make_unique
is safe for creating temporaries, whereas with explicit use ofnew
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' usenew
rather than the previous rule to "'never' usenew
except when you make aunique_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.
std::make_unique
and std::make_shared
are there for two reasons:
- So that you don't have to explicitly list the template type arguments.
- Additional exception safety over using
std::unique_ptr
orstd::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.
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.
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_uniques
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>
are now 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
.