Assume namespace std
throughout.
The C++14 committee draft N3690 defines std::make_unique
thus:
[n3690: 20.9.1.4]:
unique_ptr
creation [unique.ptr.create]
template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);
1 Remarks: This function shall not participate in overload resolution unless
T
is not an array.
2 Returns:unique_ptr<T>(new T(std::forward<Args>(args)...)).
template <class T> unique_ptr<T> make_unique(size_t n);
3 Remarks: This function shall not participate in overload resolution unless
T
is an array of unknown bound.
4 Returns:unique_ptr<T>(new typename remove_extent<T>::type[n]()).
template <class T, class... Args> unspecified make_unique(Args&&...) = delete;
5 Remarks: This function shall not participate in overload resolution unless
T
is an array of known bound.
Now, this seems to me to be about as clear as mud, and I think it needs more exposition. But, this editorial comment aside, I believe I've decoded the meanings of each variant:
template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);
Your bog-standard make_unique
for non-array types. Presumably the "remark" indicates that some form of static assertion or SFINAE trick is to prevent the template from being successfully instantiated when T
is an array type.
At a high-level, see it as the smart-pointer equivalent to T* ptr = new T(args);
.
template <class T> unique_ptr<T> make_unique(size_t n);
A variant for array types. Creates a dynamically-allocated array of n
× Ts
, and returns it wrapped in a unique_ptr<T[]>
.
At a high-level, see it as the smart-pointer equivalent to T* ptr = new T[n];
.
template <class T, class... Args> unspecified make_unique(Args&&...)
Disallowed. "unspecified" would probably be unique_ptr<T[N]>
.
Would otherwise be the smart-pointer equivalent to something like the invalid T[N]* ptr = new (keep_the_dimension_please) (the_dimension_is_constexpr) T[N];
.
First of all, am I correct? And, if so, what's going on with the third function?
If it's there to disallow programmers from attempting to dynamically-allocate an array while providing constructor arguments for each element (just as new int[5](args)
is impossible), then that's already covered by the fact that the first function cannot be instantiated for array types, isn't it?
If it's there to prevent the addition to the language of a construct like T[N]* ptr = new T[N]
(where N
is some constexpr
) then, well, why? Wouldn't it be completely possible for a unique_ptr<T[N]>
to exist that wraps a dynamically-allocated block of N
× T
s? Would this be such a bad thing, to the extent that the committee has gone out of its way to disallow its creation using make_unique
?
Why is make_unique<T[N]>
disallowed?
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.
A little late, but make_unique can itself throw according to cppreference: make_unique "may throw std::bad_alloc or any exception thrown by the constructor of T. If an exception is thrown, this function has no effect." So how is that exception safe?
Yes, all the elements will be value initialized by std::make_unique.
Quoting from the original proposal:
T[N]
As of N3485,
unique_ptr
doesn't provide a partial specialization forT[N]
. However, users will be strongly tempted to writemake_unique<T[N]>()
. This is a no-win scenario. Returningunique_ptr<T[N]>
would select the primary template for single objects, which is bizarre. Returningunique_ptr<T[]>
would be an exception to the otherwise ironclad rule thatmake_unique<something>()
returnsunique_ptr<something>
. Therefore, this proposal makesT[N]
ill-formed here, allowing implementations to emit helpfulstatic_assert
messages.
The author of the proposal, Stephan T. Lavavej, illustrates this situation in this video on Core C++ (courtesy of chris), starting from minute 1:01:10 (more or less).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With