C ++ move (): что осталось в векторе? - PullRequest
1 голос
/ 28 апреля 2020

У меня есть фрагмент кода, где в vector элементы являются парами int и string. Затем я хочу переместить все элементы из vector в unordered_map<int, string>:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <unordered_map>
#include <vector>
using namespace std;

template <typename C>
void print(const C& container) {
    for (const auto& ele : container) {
        cout << "(" << ele.first << ", " << ele.second << "), ";
    }
    cout << endl;
}

int main() {
    vector<pair<int, string>> v {
        {1, "one"},
        {2, "two"},
        {3, "three"},
        {4, "four"},
        {5, "five"}
    };
    unordered_map<int, string> uMap;

    move(begin(v), end(v), inserter(uMap, begin(uMap)));

    cout << "In unordered_map:" << endl;
    print(uMap);
    cout << endl << "In vector:" << endl;
    print(v);

    return 0;
}

Что я не понимаю, так это результаты:

In unordered_map:
(5, five), (4, four), (3, three), (2, two), (1, one), 
In vector:
(1, ), (2, ), (3, ), (4, ), (5, ),

Почему эти целые числа остались в vector? Я думал, что функция move() переместит все элементы из vector в unordered_map, так что в vector?

ничего не останется

Ответы [ 4 ]

3 голосов
/ 28 апреля 2020

Это не совсем то, что здесь означает «движение».

Да, это сбивает с толку.

Ваши новые элементы на карте будут построены с ходом из элементов в вектор. Это может включать кражу ресурсов из элементов вектора (в частности, динамически распределенные строковые данные теперь будут принадлежать новым элементам и отделяться от старых).

Но на самом деле это не так удалить оригинальные элементы. Они все еще там, в отъезде. Вы захотите clear() вектор самостоятельно.

To цитата Eljay :

std::move в некотором смысле неудачный термин. Но это было намного короче чем std::suck_out_the_guts_and_transplant_them_into_another_object_maybe.

3 голосов
/ 28 апреля 2020

С cppreference :

Перемещает элементы в диапазоне [первый, последний), в другой диапазон, начиная с d_first, начиная с первого и продолжая до последнего - 1. После этой операции элементы в диапазоне перемещения будут по-прежнему содержать допустимые значения соответствующего типа, но не обязательно те же значения, что и до перемещения.

Поскольку алгоритм работает на итераторах, существует это никоим образом не может удалить элементы из вектора. Они все еще там и могут иметь то же значение, что и раньше (но не обязательно).

Также в векторе все еще присутствуют строки. После перехода из std::string он находится в допустимом, но неопределенном состоянии. В этом случае строки пусты.

1 голос
/ 28 апреля 2020

std::move на самом деле ничего не двигает. Он просто выполняет приведение к rvalue и сообщает компилятору, что вам уже все равно, что происходит с этим объектом. В случае int компилятор решает копировать как наиболее эффективный способ.

Подробнее о семантике перемещения c ++ можно прочитать здесь: Семантика перемещения C ++

1 голос
/ 28 апреля 2020

Неформально говоря, единственное требование к удаленному объекту - это то, что он может быть безопасно уничтожен позже. В случае int лучше всего ничего не делать. Движение не уничтожает объект и не удаляет его из контейнера. Объекты все еще находятся в векторе, просто они сейчас находятся в состоянии «оттуда», что для int оказалось таким же, как и раньше.

...