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?
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