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.
make_unique<vector<int>>(10,20)
what do you want to get ? vector with 10 items, all 20 value (when () is used in make_unique), or vector with 2 items 10,20 (when {} is used, vector has constructor which takes initializer_list). – Benedettastd::is_aggregate
trait. I guess people felt it's better to have a language solution to that, rather than a library one. – Mccaffreymake_shared
. I have yet to find whymake_shared
chose one way over the other.shared_ptr
was in TR1 though, long before unified initialisation syntax existed - not certain ifmake_shared
existed back then. – Broeker