I was trying to adapt some code and moving the content from a vector to another one using emplace_back()
#include <iostream>
#include <vector>
struct obj
{
std::string name;
obj():name("NO_NAME"){}
obj(const std::string& _name):name(_name){}
obj(obj&& tmp): name(std::move(tmp.name)) {}
obj& operator=(obj&& tmp) = default;
};
int main(int argc, char* argv[])
{
std::vector<obj> v;
for( int i = 0; i < 1000; ++i )
{
v.emplace_back(obj("Jon"));
}
std::vector<obj> p;
for( int i = 0; i < 1000; ++i )
{
p.emplace_back(v[i]);
}
return(0);
}
This code doesn’t compile with g++-4.7, g++-4.6 and clang++: what it’s wrong with it ?
I always got 1 main error about
call to implicitly-deleted copy constructor of obj
?
Although the existing answer provides a workaround using
std::movethat makes your program compile, it must be said that your use ofemplace_backseems 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 ofemplace_backas a method to move elements into the vector, and ofpush_backas 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:But this is not what the difference between
emplace_backandpush_backis about.Firstly, even
push_backwill 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_backis 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 ofemplace_backare the arguments to the constructor of the object. So your loop above should really look like this: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 ofemplace_backis that you need not create the object and then move it in. You don’t benefit from that idea when you passobj("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_backto move objects that exist already. And again,emplace_backapplied 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 usepush_back, applied to the result ofstd::move:Further notes
1) You can simplify the loop above using C++11 range-based for:
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
vwill 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:This reduces the second loop to just a single line, and it makes sure the source vector is cleared.