Although the existing answer provides a workaround using std::move
that makes your program compile, it must be said that your use of emplace_back
seems to be based on a misunderstanding.
The way you describe it ("I was trying to [...] moving the content from a vector to another one using emplace_back()
") and the way you use it suggest that you think of emplace_back
as a method to move elements into the vector, and of push_back
as a method to copy elements into a vector. The code you use to fill the first instance of the vector seems to suggest this as well:
std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
v.emplace_back(obj("Jon"));
}
But this is not what the difference between emplace_back
and push_back
is about.
Firstly, even push_back
will move (not copy) the elements into the vector if only it is given an rvalue, and if the element type has a move assignment operator.
Secondly, the real use case of emplace_back
is to construct elements in place, i.e. you use it when you want to put objects into a vector that do not exist yet. The arguments of emplace_back
are the arguments to the constructor of the object. So your loop above should really look like this:
std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
v.emplace_back("Jon"); // <-- just pass the string "Jon" , not obj("Jon")
}
The reason why your existing code works is that obj("Jon")
is also a valid argument to the constructor (specifically, to the move constructor). But the main idea of emplace_back
is that you need not create the object and then move it in. You don't benefit from that idea when you pass obj("Jon")
instead of "Jon"
to it.
On the other hand, in your second loop you are dealing with objects that were created before. There is no point in using emplace_back
to move objects that exist already. And again, emplace_back
applied to an existing object does not mean that the object is moved. It only means that it is created in-place, using the ordinary copy constructor (if that exists). If you want to move it, simply use push_back
, applied to the result of std::move
:
std::vector<obj> p;
for( int i = 0; i < 1000; ++i )
{
p.push_back(std::move(v[i])); // <-- Use push_back to move existing elements
}
Further notes
1) You can simplify the loop above using C++11 range-based for:
std::vector<obj> p;
for (auto &&obj : v)
p.push_back(std::move(obj));
2) Regardless of whether you use an ordinary for-loop or range-based for, you move the elements one by one, which means that the source vector v
will remain as a vector of 1000 empty objects. If you actually want to clear the vector in the process (but still use move semantics to transport the elements to the new vector), you can use the move constructor of the vector itself:
std::vector<obj> p(std::move(v));
This reduces the second loop to just a single line, and it makes sure the source vector is cleared.