It is possible to move data from source container to destination container using the std::move_iterator
if the container has string types of data. std::move_iterator
does not operate with other data types in the container.
std::move_iterator works fine
#include <iostream> // std::cout
#include <iterator> // std::move_iterator
#include <vector> // std::vector
#include <string> // std::string
#include <algorithm> // std::copy
using namespace std;
int main () {
vector<string>src = {"one", "two", "three", "four"}, des(4);
using Iter = vector<string>::iterator;
//move the data from src to des
move_iterator<Iter>beginitr(src.begin());
move_iterator<Iter>enditr(src.end());
Iter diter = des.begin();
while(beginitr != enditr)
{
*diter++ = *beginitr++;
}
cout << "src container size: " << src.size() << endl;
cout << "data: " ;
for_each(begin(src),end(src), [](string x){cout << x ;});
cout << endl << "THE END";
return 0;
}
output
src container size: 4
data:
THE END
std::move_iterator dose not move the data
#include <iostream> // std::cout
#include <iterator> // std::move_iterator
#include <list> // std::vector
#include <string> // std::string
#include <algorithm> // std::copy
using namespace std;
int main () {
list<int>src = {1,2,3,4}, des(4);
using Iter = list<int>::iterator;
//move the data from src to des
move_iterator<Iter>beginitr = make_move_iterator(src.begin());
move_iterator<Iter>enditr = make_move_iterator(src.end());
Iter diter = des.begin();
while(beginitr != enditr)
{
*diter++ = *beginitr++;
}
cout << "src container size: " << src.size() << endl;
for_each(begin(src),end(src), [](int x){cout << x << endl;});
return 0;
}
output
src container size: 4
1
2
3
4
It appears that integer data gets copied to the target container rather than being moved.
The only difference using a move iterator makes is that dereferencing the iterator yields an rvalue reference. If only the copy assignment operator is available, but no move assignment operator, this will be used as "fallback".
The following code demonstrates this:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>
#include <utility>
struct Test
{
#if 0
Test(Test&&)
{
std::cout << "Test::Test(Test&&)\n";
}
Test& operator=(Test&&)
{
std::cout << "Test& Test::operator=(Test&&)\n";
return *this;
}
#endif
Test(Test const&)
{
std::cout << "Test::Test(Test const&)\n";
}
Test& operator=(Test const&)
{
std::cout << "Test& Test::operator=(Test const&)\n";
return *this;
}
Test()
{
std::cout << "Test::Test()\n";
}
};
int main() {
std::list<Test> src(4);
std::list<Test> des(4);
std::cout << "-------------------copy with move iterator--------------------\n";
std::copy(std::make_move_iterator(src.begin()), std::make_move_iterator(src.end()), des.begin());
std::cout << "-------------------copy with normal iterator--------------------\n";
std::copy(src.begin(), src.end(), des.begin());
}
Output with #if 0
left as is:
...
-------------------copy with move iterator--------------------
Test& Test::operator=(Test const&)
Test& Test::operator=(Test const&)
Test& Test::operator=(Test const&)
Test& Test::operator=(Test const&)
-------------------copy with normal iterator--------------------
Test& Test::operator=(Test const&)
Test& Test::operator=(Test const&)
Test& Test::operator=(Test const&)
Test& Test::operator=(Test const&)
Output with move semantics defined (#if 1
instead of #if 0
):
...
-------------------copy with move iterator--------------------
Test& Test::operator=(Test&&)
Test& Test::operator=(Test&&)
Test& Test::operator=(Test&&)
Test& Test::operator=(Test&&)
-------------------copy with normal iterator--------------------
Test& Test::operator=(Test const&)
Test& Test::operator=(Test const&)
Test& Test::operator=(Test const&)
Test& Test::operator=(Test const&)
For arithmetic types like int
there are only copy semantics, not move semantics leaving the source list unmodified in your code.