Differences between std::make_unique and std::unique_ptr with new
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.
Differences between std::make_unique and std::unique_ptr with new internally
What do these functions do exactly and where is the difference?
Nothing magical actually. They just transform user code from this:
f( std::unique_ptr<T1>{ new T1 }, std::unique_ptr<T2>{ new T2 } );
Into this:
f( make_unique<T1>(), make_unique<T2>() );
Just to avoid the scenario where the compiler orders the actions like the following, because it may do so until C++14 (included):
new T1
new T2
- build first
unique_ptr
- build second
unique_ptr
If the second step (new T2
) throws an exception, the first allocated object has not yet been secured into a unique_ptr
and leaks.
The make_unique
function is actually simple to write, and has been overlooked for C++11. It has been easily introduced in C++14. Inbetween, everybody would write their own make_unique
template, or google the one written by Stephen T. Lavavej.
As StoryTeller commented, since C++17, this interleaving is no more allowed.
Advantages of using std::make_unique over new operator
Advantages
make_unique
teaches users "never saynew
/delete
andnew[]
/delete[]
" without disclaimers.make_unique
shares two advantages withmake_shared
(excluding the third advantage, increased efficiency). First,unique_ptr<LongTypeName> up(new LongTypeName(args))
must mentionLongTypeName
twice, whileauto up = make_unique<LongTypeName>(args)
mentions it once.make_unique
prevents the unspecified-evaluation-order
leak triggered by expressions likefoo(unique_ptr<X>(new X), unique_ptr<Y>(new Y))
. (Following the advice "never saynew
" is simpler than
"never saynew
, unless you immediately give it to a namedunique_ptr
".)make_unique
is carefully implemented for exception safety and is recommended over directly callingunique_ptr
constructors.
When not to use make_unique
- Don't use
make_unique
if you need a custom deleter or are adopting a raw pointer from elsewhere.
Sources
- Proposal of
std::make_unique
. - Herb Sutter's GotW #89 Solution: Smart Pointers
Why does C++ need std::make_unique over forwarded unique_ptr constructor?
I want to summarize discussion with Some programmer dude, StoryTeller - Unslander Monica and Raymond Chen
So, there are 2 reasons:
std::make_unique
pairs well with std::make_shared which was introduced earlier so this was easier to learn than new constructor forunique_ptr
.- There is possible ambiguity between constructor of
unique_ptr
and constructor of inner value type (T
) if this type have own constructor which takes a pointer to self type. E.g.
struct Inner{
Inner() = default;
Inner(Inner* parent_node): parent(parent_node){}
Inner* parent = nullptr;
};
Inner* parent = make_parent();
// It would be not clear for human which constructor must be called here
std::unique_ptr<Inner> child(parent);
Compiler can deduce which constructor should be called here but it is hard for human. So having function std::make_unique
is beneficial because it is clear that all constructors of std::unique_ptr
create only unique_ptr and never call inner value constructor while std::make_unique
would always call constructor of inner value. This makes code much easier to reason about.
Thanks to everyone for discussion!
The difference between make_uniqueT() and unique_ptrT(new T)
Not from the specification, but this std::make_unique
reference says that the array-creation overload is equivalent to
unique_ptr<T>(new typename std::remove_extent<T>::type[size]())
The allocation is basically equivalent to
new T[size]()
which according to this new
reference (construction section) means each element is value-initialized.
For an array of primitive types, like char
, that means each element is initialized to zero.
When you don't value-initialize the array, the array elements will be default constructed, or (for primitive types) will not be initialized at all.
Not initializing a large array is quick. Initializing it, even to all zeroes, is not as quick. Which should explain the difference in execution time.
Strange behavior between `std::make_unique` and `std::unique_ptr` with forward declaration
Why
std::make_unique<View>(shared_from_this())
works even if there is only a forward delaration forView
beforeDatabase
's definition, whereas the compiler complains aboutstd::unique_ptr<View>(new View(shared_from_this())
under the same condition?
Consider this simplified example:
#include <memory>
struct foo;
std::unique_ptr<foo> make_foo_1() { return std::make_unique<foo>(); } // OK
std::unique_ptr<foo> make_foo_2() { return std::unique_ptr<foo>(new foo); } // ERROR
struct foo {};
In make_foo_1
, std::unique_ptr<foo>
is made a dependent type in make_unique<foo>
which means that it'll postpone binding to unique_ptr<foo>
.
But "Non-dependent names are looked up and bound at the point of template definition" (i.e., the definition of std::unique_ptr<foo>
) which means that, in make_foo_2
, the definition of foo
must have already been seen by the compiler or else it'll complain about foo
being an incomplete type.
Why use std::make_unique in C++17?
You're right that the main reason was removed. There are still the don't use new guidelines and that it is less typing reasons (don't have to repeat the type or use the word new
). Admittedly those aren't strong arguments but I really like not seeing new
in my code.
Also don't forget about consistency. You absolutely should be using make_shared
so using make_unique
is natural and fits the pattern. It's then trivial to change std::make_unique<MyClass>(param)
to std::make_shared<MyClass>(param)
(or the reverse) where the syntax A requires much more of a rewrite.
Related Topics
How to Detect Reliably MAC Os X, Ios, Linux, Windows in C Preprocessor
Constructor Initialization-List Evaluation Order
Inline Functions VS Preprocessor Macros
Why Is It Wrong to Use Std::Auto_Ptr≪≫ With Standard Containers
How to Convert an Enum Type Variable to a String
What Is the Closest Thing Windows Has to Fork()
Unicode Encoding For String Literals in C++11
Why Copying Stringstream Is Not Allowed
What Is the Best Open Xml Parser For C++
How to Safely Pass Objects, Especially Stl Objects, to and from a Dll
What Are All the Member-Functions Created by Compiler For a Class? Does That Happen All the Time
Catching Exception: Divide by Zero
How to Handle Wrong Data Type Input
When I Change a Parameter Inside a Function, Does It Change For the Caller, Too
How to Implement the Factory Method Pattern in C++ Correctly