Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is `make_unique<T[N]>` disallowed?

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:

  1. 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);.

  2. 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];.

  3. 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 × Ts? 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?

like image 846
Lightness Races in Orbit Avatar asked May 16 '13 20:05

Lightness Races in Orbit


People also ask

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.

Does Make_unique throw?

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?

Does Make_unique initialize memory?

Yes, all the elements will be value initialized by std::make_unique.


1 Answers

Quoting from the original proposal:

T[N]

As of N3485, unique_ptr doesn't provide a partial specialization for T[N]. However, users will be strongly tempted to write make_unique<T[N]>(). This is a no-win scenario. Returning unique_ptr<T[N]> would select the primary template for single objects, which is bizarre. Returning unique_ptr<T[]> would be an exception to the otherwise ironclad rule that make_unique<something>() returns unique_ptr<something>. Therefore, this proposal makes T[N] ill-formed here, allowing implementations to emit helpful static_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).

like image 57
Andy Prowl Avatar answered Sep 24 '22 12:09

Andy Prowl