I was under the impression that, since std::initializer_list<T>
will initialize with copying T's into storage, this would not work:
struct t{};
std::initializer_list<std::unique_ptr<t>> l{std::make_unique<t>(), std::make_unique<t>()};
But it does work and the above initializer_list<std::unique_ptr<t>>
can be initialized with std::unique_ptr<t>
which, by itself, has its copy constructor deleted.
How is the above syntax possible, while initializing a std::vector<std::unique_ptr<t>>
with a similar std::initializer_list<>
would fail?
I think your misunderstanding lies in the phrase, "will initialize with copying T's into storage". This is not – strictly speaking – necessarily true.
Although each element of a std:initializer_list
is copy-initialized§, that doesn't necessarily mean it is actually copied. That is, the type, T
doesn't actually need a copy constructor because a move constructor will be used if that is available (as it is for std::unique_ptr<T>
) and the copy constructor is not. Note also that, when a std::initializer_list
is copied, its underlying elements are not copied.
In the case where you attempt to use a std::initializer_list<std::unique_ptr>
to construct a std::vector<std::unique_ptr>
, the issue is a bit trickier. That argument (the initializer-list) can be created but then, internally, the vector needs to move the elements of that list into its own container. But it can't do this, because the "underlying array" of a std::initializer_list
is treated as an array of type const T[]
¶, so a move constructor won't/can't work on its elements.
§ From the linked cppreference page:
If other is an rvalue expression, a move constructor will be selected by overload resolution and called during copy-initialization. This is still considered copy-initialization; there is no special term (e.g., move-initialization) for this case.
¶ From the std::initializer_list cppreference page:
The underlying array is a temporary array of type
const T[N]
, in which each element is copy-initialized (except that narrowing conversions are invalid) from the corresponding element of the original initializer list. The lifetime of the underlying array is the same as any other temporary object, except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary (with the same exceptions, such as for initializing a non-static class member). The underlying array may be allocated in read-only memory.
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