c++ конкатенация (объединение) 2х векторов

Рейтинг: 0Ответов: 1Опубликовано: 06.05.2023

Какой самый быстрый способ объединения 2х векторов (std::vector)? Т.е. присоединить вектор 2 к вектору 1. Нужен вариант как с move семантикой, чтобы вектор 2 был пустым, так и с копированием (наиболее быстрым), и еще для POD типов (опять таки быстрый). Ну и как дополнение к вопросу: а если нужно соединить более 2х векторов?

Ответы

▲ 2Принят

Ниже функция которая переносит элементы вектора b в конец вектора a. Если вы хотите использовать её много раз с одним и тем же вектором a, рекомендую вызвать a.reserve() с размером равным длине ожидаемого результата.

Если вы не хотите разрушать элементы b, уберите вызовы std::make_move_iterator.

template<typename Item>
void concat(std::vector<Item> &a, std::vector<Item> &b) {
    a.insert(
        a.end(),
        std::make_move_iterator(b.begin()),
        std::make_move_iterator(b.end())
    );
}

Этот код работает одинаково хорошо и для POD и для сложных типов с конструкторами. Например берём код

struct S { int i; };

void concat(std::vector<S> &a, std::vector<S> &b) {
    a.insert(
        a.end(),
        std::make_move_iterator(b.begin()),
        std::make_move_iterator(b.end())
    );
}

Компилируем его с оптимизацией в ассемблер: g++ -S -O3 concat.cpp. В файле concat.s можно найти код в котором в основной ветке, когда места в векторе a достаточно, вызывается call memmove один раз. Если места недостаточно, то в коде выделяется новая память и делаются два вызова call memcpy (старые данные a) и call memove (новые данные из b). Циклов нигде нет, всё настолько оптимально насколько возможно.

Если тип имеет нетривиальный конструктор, без циклов не обойдётся. Но тут уж ничего не поделаешь.