Подтвердить что ты не робот

Существует ли стандартный способ перемещения диапазона в вектор?

Рассмотрим следующую программу, которая вставляет диапазон элементов в вектор:

vector<string> v1;
vector<string> v2;

v1.push_back("one");
v1.push_back("two");
v1.push_back("three");

v2.push_back("four");
v2.push_back("five");
v2.push_back("six");

v1.insert(v1.end(), v2.begin(), v2.end());

Это эффективно копирует диапазон, выделяя достаточное пространство в целевом векторе для всего диапазона, чтобы потребовалось не более одного изменения размера. Теперь рассмотрим следующую программу, которая пытается переместить диапазон в вектор:

vector<string> v1;
vector<string> v2;

v1.push_back("one");
v1.push_back("two");
v1.push_back("three");

v2.push_back("four");
v2.push_back("five");
v2.push_back("six");

for_each ( v2.begin(), v2.end(), [&v1]( string & s )
{
    v1.emplace_back(std::move(s));
});

Выполняет успешный ход, но не обладает преимуществами, которые insert() имеет в отношении предварительного распределения места в целевом векторе, поэтому вектор может быть изменен несколько раз во время операции.

Итак, мой вопрос: есть ли эквивалент вставки, который может перемещать диапазон в вектор?

4b9b3361

Ответ 1

Вы используете move_iterator с insert:

v1.insert(v1.end(), make_move_iterator(v2.begin()), make_move_iterator(v2.end()));

Пример в 24.5.3 почти такой же.

Вы получите нужную оптимизацию, если (a) vector::insert использует отправку итератора-тега для обнаружения итератора с произвольным доступом и предсказывает размер (который вы предположили в своем примере, который копирует), и (b) move_iterator сохраняет категорию итератора итератора, который он обертывает (что требуется стандартом).

В неясной точке: я уверен, что vector::insert может помещаться из источника (что здесь не имеет значения, поскольку источник является тем же типом, что и пункт назначения, поэтому emplace совпадает с копией/перемещением, но будет иметь отношение к другим идентичным примерам). Я еще не нашел выражение о том, что это необходимо для этого, я просто сделал вывод, что требование к паре итератора i,j, переданное в insert, состоит в том, что T be EmplaceConstructible from *i.

Ответ 2

  • std::move алгоритм с preallocation:

    #include <iterator>
    #include <algorithm>
    
    v1.reserve(v1.size() + v2.size()); // optional
    std::move(v2.begin(), v2.end(), std::back_inserter(v1));
    
  • Далее было бы более гибким:

    v1.insert(v1.end(), 
         std::make_move_iterator(v2.begin()), 
         std::make_move_iterator(v2.end()));
    
    Стив Джессоп представил справочную информацию о том, что он делает, и, возможно, о том, как он это делает.