Why is the copy constructor called in the std :: vector initializer list?

I have the following very simple class:

class Foo { public: Foo() {} Foo(const Foo&) = delete; Foo(Foo&&) {} void operator=(const Foo&) = delete; void operator=(Foo&&) {} void dump() const {} }; 

A class moves constructively and is assigned, but it is not copied constructively and assigned.

I would like to initialize the vector of Foo elements using the vector list of initializers.

 std::vector<Foo> vf = { Foo() }; 

The compiler complains because the code must use the remote copy constructor. Can someone explain why the move construct is not used in this case and why a copy of the object is needed?

The following also requires a copy constructor and does not work:

 std::vector<Foo> vf = { std::move(Foo()) }; 

On the other hand, this works fine (the move constructor is called):

 std::vector<Foo> vf; vf.push_back(Foo()); 

Thanks for the explanation...:)

Update:

The article suggested by this explains my question.

Also, consider the following code (along with class Foo above):

 class Bar { public: Bar(std::initializer_list<Foo> _l) { std::cout << "Bar::Bar()" << std::endl; for (auto& e : _l) e.dump(); } }; int main() { Bar b { Foo() }; return 0; } 

This creates the following result (compiled with C ++ 11):

 Foo::Foo() Bar::Bar() Foo::dump() Foo::~Foo() 

You can see that the list of initializers is actually not filled with the "copy of objects" specified between curly braces. This may not be correct from C ++ 14.

+10
source share
3 answers

This is special because you are using a list of initializers that uses a copy constructor. The initializer list is initialized with a copy of the object, and then passed to the vector.

If you read the linked link, from C ++ 14 it even explicitly says

... each element is copied-initialized ... from the corresponding element of the initial list of initializers

Emphasis on mine

+9
source

std::initializer_list does not work for move-only types. See this question for more details.

Fortunately, there is a dead relief for you:

 std::vector<foo> vf (1); 

This initializes the vector with 1 built by default foo .

0
source

In general, the requirements for a std::vector elements are that the element type is a full type and meets the Erasable requirements. As such, there is no problem with your subject.

However, initializing with a list of initializers as such:

 std::vector<Foo> vf = { Foo() }; 

It is required that the temporary object Foo() in the list be copied to a vector. Therefore, the compiler complains because you already made your object not copied.

You can do what you want as follows:

 std::vector<Foo> vf(1); 
0
source

All Articles