Похоже, что std::move_iterator работает только со строковыми типами данных

Можно переместить данные из исходного контейнера в целевой контейнер с помощью 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::move без итераторов. Перемещение должно быть более быстрой альтернативой копированию, которое оставляет оригинал в неопределенном состоянии, а обнуление перемещенного целого числа медленнее, чем нет.

HolyBlackCat 17.06.2023 14:07

В отличие от std::string перемещение примитивных типов делает копию, что для них дешево. Кроме того, не то чтобы std::move или std::move_iter ничего не перемещали, скорее приводили к типу rvalue. Перемещение происходит автоматически, если применимо. Например, std::move(src) сработало бы в обоих случаях.

JeJo 17.06.2023 14:07

Примечание: относительно использования пространства имен std.

wohlstad 17.06.2023 14:32

std::move_iterator работает как со строковыми, так и с целыми типами. Похоже, есть непонимание того, что делает move: перемещает ресурсы с одного объекта на другой, копирует остальное. Исходный объект «выпотрошен»; выдолбленная оболочка, подходящая для уничтожения или переназначения (для большинства стандартных типов библиотек; ваши собственные типы могут иметь другие гарантии после перемещения). («Приведение» move просто позволяет рассматривать lvalue как rvalue для целей построения или назначения.) A string имеет ресурсы; int нет.

Eljay 17.06.2023 14:40

Стандартные типы, перемещенные из стандартных, будут находиться в «действительном, но неуказанном состоянии». «Неизменный» — это абсолютно правильное состояние, поэтому оно соответствует.

BoP 17.06.2023 14:57

Всем спасибо за подробное объяснение.

Hardik 18.06.2023 06:56
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Единственное различие с использованием итератора перемещения состоит в том, что разыменование итератора дает ссылку на 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&)

Демо Godbolt

Для арифметических типов, таких как int, существует только семантика копирования, а не семантика перемещения, оставляющая исходный список без изменений в вашем коде.

Спасибо за подробное объяснение.

Hardik 18.06.2023 06:57

Другие вопросы по теме

Похожие вопросы