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
The difference is that std::make_unique
returns an object of type std::unique_ptr
and new
returns a pointer to the created object. For memory allocation failures, they will both throw. Hold on, it's not that simple. Read further.
Consider such a function below:
void func(ClassA* a, ClassB* b){
......
}
When you make a call like func(new A(), new B())
; The compiler may choose to evaluate the function arguments from left to right, or in any order it so wishes. Let's assume left to right evaluation: What happens when the first new
expression succeeds but the second new
expression throws?
The real danger here is when you catch such exception; Yes, you may have caught the exception thrown by new B()
, and resume normal execution, but new A()
already succeeded, and its memory will be silently leaked. Nobody to clean it up... * sobs...
But with make_unique
, you cannot have a leak because, stack unwinding will happen ( and the destructor of the previously created object will run). Hence, having a preference for make_unique
will constrain you towards exception safety. In this case, std::make_unique
provides a "Basic Exception Safety" that the memory allocated and object created by new
will never be orphaned no matter what. Even till the ends of time... :-)
You should read Herb Sutter GoTW102