The usefulness of std :: make_unique and std :: make_shared in C ++ 1z

With C ++ 17, we get template type output for class templates. Therefore, many make functions may be deprecated.

What about make_unique and make_shared ?

So we can write

 unique_ptr myPtr(new MyType()); // vs auto myPtr = make_unique<MyType>(); 

can we forget about these features?

+7
c ++ c ++ 17
source share
2 answers

Neither unique_ptr nor shared_ptr can be built without explicitly specifying a type due to the inability to distinguish between T* and T[] . The spelling unique_ptr{new int} poorly formed.

Also, std::make_shared does more than just construct std::shared_ptr for you without having to type new . It also highlights both the object and the management structure in one distribution, which saves your distribution and gives you the terrain when you need to change the reference count.

+18
source share

You forgot about one of the most important reasons why we got make_unique . Consider the difference between these two function calls:

 some_function(make_unique<T>(), std::vector<U>{1, 2, 3}); some_function(unique_ptr(new T()), std::vector<U>{1, 2, 3}); 

One of these functions has a subtle error. Can you guess what it is?

If the vector constructor throws, then something really bad can happen. Due to the rules for evaluating the expression of the arguments of a C ++ function, it is possible that the evaluation order may be new T() , followed by std::vector<U>{1, 2, 3} , followed by the unique_ptr<T> constructor. If vector throws, then the new ed pointer is never freed.

This is bad. And this is about 90% of the reasons why we have make_unique in general.

Now, having said that, C ++ 17 also makes changes to the evaluation of function argument expressions, which makes this point obsolete. C ++ 17 rules guarantee that there can be no match between the various expressions that initialize the arguments. That is, each argument initializer expression completes completely before the other starts. C ++ 17 does not guarantee the order in which arguments are expressed, but there can be no alternation between subexpressions.

In the above code, the evaluation order can be first vector or new T() . But if he first evaluates new T() , he must evaluate unique_ptr<T>() before evaluating the vector constructor.

So, in C ++ 17, both of them are safe. Thus, although the output of the template argument is not deprecated by make_unique , C ++ 17 generally does.

Of course, there is always the problem of standard matching. The compiler can implement the output of the constructor argument before implementing the rules for ordering the evaluation of an expression. And there is no way to make your code broken if the evaluation order of the expression does not exist (unless you rely on function validation macros that some compilers do not support).

To be safe, I suggest sticking with make_unique in such circumstances.

And finally, there is a feature of make/allocate_shared : the ability to allocate a control unit and an object in the same store. This is not an insignificant feature of shared_ptr , and it cannot be replicated using the new template.

Therefore, you should continue to use make_shared , if possible.

+5
source share

All Articles