Differences between std::make_unique and std::unique_ptr with new
Solution 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.
Solution 2
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.
Solution 3
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.
Solution 4
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
.
Related videos on Youtube
NFRCR
Updated on December 03, 2020Comments
-
NFRCR over 3 years
Does
std::make_unique
have any efficiency benefits likestd::make_shared
?Compared to manually constructing
std::unique_ptr
:std::make_unique<int>(1); // vs std::unique_ptr<int>(new int(1));
-
Ed Heal about 10 yearsDoes
make_shared
have any efficiency over just writing the long hand code? -
bames53 about 10 years@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 useweak_ptr
a lot then you may end up using more memory. -
Ed Heal about 10 yearsPerhaps this is a good starting point stackoverflow.com/questions/9302296/…
-
Krishna Kanth Yenumula almost 3 yearsSee this link for detailed explanation: herbsutter.com/gotw/_102
-
-
David G about 10 yearsThey're also there for exception-safety.
-
Timothy Shields about 10 years@0x499602D2 And that, good addition. This page talks about that.
-
Timothy Shields about 10 yearsIt would make more sense to say
std::unique_ptr
andstd::shared_ptr
are why we can tell people to "never usenew
." -
bames53 about 10 years@TimothyShields Yeah, that's what I mean. It's just that in C++11 we have
make_shared
and somake_unique
is the final piece that was previously missing. -
Dan Nissenbaum about 8 yearsAny way you could mention briefly, or link to, the reason for not using unnamed temporaries?
-
Dan Nissenbaum about 8 yearsActually, 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 iffunction_that_can_throw
actually throws then you leak.make_unique
prevents this case. So, my question is answered. -
Daniel over 7 years@bames53 Unfortunately there is still need to use raw
new
if you want to pass a custom facet tostd::locale
(overload 7). -
tambre about 7 years@bames53 Have there been any news regarding the footnote?
-
bames53 about 7 years@tambre The linked papers are part of the C++17 draft, and there shouldn't be any significant changes between now and publication later this year. Clang already implements these rules. It's not clear from gcc's status page if they do or not yet.
-
Passer By almost 7 yearsTook a really long time to see why it is now safe, but yeah it is. BTW thanks for updating your answer
-
Patrick almost 5 yearsOne 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>.
-
MathBunny over 4 yearsFor 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. -
nyanpasu64 over 2 yearsIs there a plan to fix C++ so make_unique and make_shared can access private constructors?
-
Volodymyr Lashko over 2 years@nyanpasu64 make_unique needs no fixing. You can always make it a friend of your class with a private constructor.