Am I allowed to move elements out of a std::initializer_list<T>
?
#include <initializer_list> #include <utility> template<typename T> void foo(std::initializer_list<T> list) { for (auto it = list.begin(); it != list.end(); ++it) { bar(std::move(*it)); // kosher? } }
Since std::intializer_list<T>
requires special compiler attention and does not have value semantics like normal containers of the C++ standard library, I'd rather be safe than sorry and ask.
Move semantics is a set of semantic rules and tools of the C++ language. It was designed to move objects, whose lifetime expires, instead of copying them. The data is transferred from one object to another. In most cases, the data transfer does not move this data physically in memory.
That's what rvalue references and move semantics are for! Move semantics allows you to avoid unnecessary copies when working with temporary objects that are about to evaporate, and whose resources can safely be taken from that temporary object and used by another.
An object of type std::initializer_list<T> is a lightweight proxy object that provides access to an array of objects of type const T .
No, that won't work as intended; you will still get copies. I'm pretty surprised by this, as I'd thought that initializer_list
existed to keep an array of temporaries until they were move
'd.
begin
and end
for initializer_list
return const T *
, so the result of move
in your code is T const &&
— an immutable rvalue reference. Such an expression can't meaningfully be moved from. It will bind to an function parameter of type T const &
because rvalues do bind to const lvalue references, and you will still see copy semantics.
Probably the reason for this is so the compiler can elect to make the initializer_list
a statically-initialized constant, but it seems it would be cleaner to make its type initializer_list
or const initializer_list
at the compiler's discretion, so the user doesn't know whether to expect a const
or mutable result from begin
and end
. But that's just my gut feeling, probably there's a good reason I'm wrong.
Update: I've written an ISO proposal for initializer_list
support of move-only types. It's only a first draft, and it's not implemented anywhere yet, but you can see it for more analysis of the problem.
bar(std::move(*it)); // kosher?
Not in the way that you intend. You cannot move a const
object. And std::initializer_list
only provides const
access to its elements. So the type of it
is const T *
.
Your attempt to call std::move(*it)
will only result in an l-value. IE: a copy.
std::initializer_list
references static memory. That's what the class is for. You cannot move from static memory, because movement implies changing it. You can only copy from it.
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