简体   繁体   中英

Why does C++ need std::make_unique over forwarded unique_ptr constructor?

I don't ask about new operator like here . Please, read question carefully.

I want to know why we need special function make_unique over special constructor of unique_ptr.

unique_ptr could use constructor like this to make make_unique unneccessary:

template<typename T, typename ...TArgs>
unique_ptr::unique_ptr(TArgs&&... args)
        : inner_ptr(new T(std::forward(args)...))
{}

There's a couple of reasons for this.

The first has to do with a bit of C++ history. Prior to C++17, there was no exception safety with the constructor, so doing the following:

some_func(std::unique_ptr<T1>(), std::unique_ptr<T2>())

would leak memory were the constructor for T1 to throw an exception, as the C++ standard did not require that, in this case the first unique_ptr, should have it's memory deallocated. This is no longer the case since C++17

Second, it allows for a more general rule of "never to use new " which without make_unique would be "never use new except for when using unique_ptr or shared_ptr "

Also there's the added bonus of no redundant typing, as with the constructor you have to do:

auto p = std::unique_ptr<T>(new T());

listing T twice, which can be particularly ugly in the case of long type names. With make_unique this shortens to

auto p = std::make_unique<T>();

I want to summarize discussion with Some programmer dude , StoryTeller - Unslander Monica and Raymond Chen

So, there are 2 reasons:

  1. std::make_unique pairs well withstd::make_shared which was introduced earlier so this was easier to learn than new constructor for unique_ptr .
  2. 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. Eg
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 technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM