Можно переместить данные из исходного контейнера в целевой контейнер с помощью move_iterator, если контейнер имеет строковые типы данных. Move_iterator не работает с другими типами данных в контейнере.
move_iterator отлично работает
#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;
}
выход
размер контейнера src: 4 данные: КОНЕЦ
move_iterator не перемещает данные
#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;
}
выход
размер контейнера src: 4 1 2 3 4
Похоже, что целочисленные данные копируются в целевой контейнер, а не перемещаются.
В отличие от std::string перемещение примитивных типов делает копию, что для них дешево. Кроме того, не то чтобы std::move или std::move_iter ничего не перемещали, скорее приводили к типу rvalue. Перемещение происходит автоматически, если применимо. Например, std::move(src) сработало бы в обоих случаях.
Примечание: относительно использования пространства имен std.
std::move_iterator работает как со строковыми, так и с целыми типами. Похоже, есть непонимание того, что делает move: перемещает ресурсы с одного объекта на другой, копирует остальное. Исходный объект «выпотрошен»; выдолбленная оболочка, подходящая для уничтожения или переназначения (для большинства стандартных типов библиотек; ваши собственные типы могут иметь другие гарантии после перемещения). («Приведение» move просто позволяет рассматривать lvalue как rvalue для целей построения или назначения.) A string имеет ресурсы; int нет.
Стандартные типы, перемещенные из стандартных, будут находиться в «действительном, но неуказанном состоянии». «Неизменный» — это абсолютно правильное состояние, поэтому оно соответствует.
Всем спасибо за подробное объяснение.





Единственное различие с использованием итератора перемещения состоит в том, что разыменование итератора дает ссылку на rvalue. Если доступен только оператор присваивания копирования, но нет оператора присваивания перемещения, он будет использоваться как «откат».
Следующий код демонстрирует это:
#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());
}
Вывод с #if 0 оставленным как есть:
...
-------------------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&)
Вывод с определенной семантикой перемещения (#if 1 вместо #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&)
Для арифметических типов, таких как int, существует только семантика копирования, а не семантика перемещения, оставляющая исходный список без изменений в вашем коде.
Спасибо за подробное объяснение.
Копирование целого числа аналогично его копированию. Вы можете воспроизвести это с помощью одного
std::moveбез итераторов. Перемещение должно быть более быстрой альтернативой копированию, которое оставляет оригинал в неопределенном состоянии, а обнуление перемещенного целого числа медленнее, чем нет.