Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

initializer_list and move semantics

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.

like image 264
fredoverflow Avatar asked Nov 19 '11 09:11

fredoverflow


People also ask

What is a move semantic?

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.

When should I use move semantics?

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.

What is std :: Initializer_list?

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 .


2 Answers

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.

like image 115
Potatoswatter Avatar answered Oct 29 '22 13:10

Potatoswatter


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.

like image 31
Nicol Bolas Avatar answered Oct 29 '22 12:10

Nicol Bolas