Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

make_unique with brace initialization

https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique writes that std::make_unique can be implemented as

template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) {     return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); } 

This does not work for plain structs with no constructors. Those can be brace-initialized but don't have a non-default constructor. Example:

#include <memory> struct point { int x, z; }; int main() { std::make_unique<point>(1, 2); } 

Compiling this will have the compiler complain about lack of a 2-argument constructor, and rightly so.

I wonder, is there any technical reason not to define the function in terms of brace initialization instead? As in

template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) {     return std::unique_ptr<T>(new T{std::forward<Args>(args)...}); } 

That works well enough for the scenario above. Are there any other legitimate use cases this would break?

Seeing how the general trend appears to prefer braces for initialization, I would assume making braces in that template would be the canonical choice, but the fact that the standard doesn't do it might be an indication of me missing something.

like image 214
MvG Avatar asked Mar 13 '19 12:03

MvG


People also ask

Does Make_unique initialize?

Yes, all the elements will be value initialized by std::make_unique. This is the initialization performed when a variable is constructed with an empty initializer.

Does Make_unique use new?

make_unique teaches users "never say new / delete and new[] / delete[] " without disclaimers. make_unique shares two advantages with make_shared (excluding the third advantage, increased efficiency).

Should I use Make_unique?

It is recommended to use the 'make_unique/make_shared' function to create smart pointers. The analyzer recommends that you create a smart pointer by calling the 'make_unique' / 'make_shared' function rather than by calling a constructor accepting a raw pointer to the resource as a parameter.

What is std :: Make_unique?

std::make_uniqueConstructs an object of type T and wraps it in a std::unique_ptr. 1) Constructs a non-array type T . The arguments args are passed to the constructor of T . The function does not participate in the overload resolution if T is an array type.


1 Answers

In C++20, this will compile:

std::make_unique<point>(1, 2); 

due to the new rule allowing initializing aggregates from a parenthesized list of values.


In C++17, you can just do:

std::unique_ptr<point>(new point{1, 2}); 

That won't work with make_shared though. So you can also just create a factory (forwarding left as an exercise):

template <typename... Args> struct braced_init {     braced_init(Args... args) : args(args...) { }     std::tuple<Args...> args;      template <typename T>     operator T() const {         return std::apply([](Args... args){             return T{args...};         }, args);     } };  std::make_unique<point>(braced_init(1, 2)); 

In C++14, you'll have to implement apply and write a factory function for braced_init because there's no CTAD yet - but these are doable.


Seeing how the general trend appears to prefer braces for initialization

Citation needed. It's a charged topic - but I definitely disagree with the claim.

like image 93
Barry Avatar answered Sep 17 '22 15:09

Barry