Как объединить два std::vector в C++? Правильные способы конкатенации
Самый простой и правильный способ: insert + reserve
Лучший способ объединить два std::vector без изменения исходных — создать новый вектор и использовать метод insert с предварительным резервированием памяти. Вот стандартное решение:
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec1 = {1, 2, 3, 4, 5};
std::vector<int> vec2 = {6, 7, 8, 9, 10};
// Шаг 1: создаём результирующий вектор
std::vector<int> result;
// Шаг 2: резервируем память сразу для всех элементов (оптимизация)
result.reserve(vec1.size() + vec2.size());
// Шаг 3: вставляем элементы первого вектора
result.insert(result.end(), vec1.begin(), vec1.end());
// Шаг 4: вставляем элементы второго вектора
result.insert(result.end(), vec2.begin(), vec2.end());
// Вывод результата
for (int x : result) {
std::cout << x << " ";
}
// Выведет: 1 2 3 4 5 6 7 8 9 10
return 0;
}
Почему это работает и почему это лучший вариант?
- Не изменяет исходные векторы — мы работаем только с новым
result. - Метод
insertс итераторами — копирует диапазон элементов из одного контейнера в другой. Это стандартный идиоматичный способ в C++. reserve— выделяет память заранее, чтобы избежать множественных переаллокаций при вставке. Безreserveвектор мог бы перераспределять память несколько раз, что снижает производительность.- Сложность — O(N+M) по времени, где N и M — размеры векторов. Это оптимально, так как нужно скопировать все элементы.
Альтернативы с использованием инициализации списком (C++11)
Если вам нужно создать вектор сразу с элементами из двух исходных, можно использовать конструктор с итераторами:
std::vector<int> result(vec1.begin(), vec1.end());
result.insert(result.end(), vec2.begin(), vec2.end());
Это эквивалентно первому варианту, но без явного reserve (хотя многие компиляторы оптимизируют это). Для максимальной производительности всё же добавляйте reserve.
Использование std::merge (для отсортированных векторов)
Если ваши векторы уже отсортированы, std::merge — идеальный выбор:
#include <algorithm>
std::vector<int> result;
result.reserve(vec1.size() + vec2.size());
std::merge(vec1.begin(), vec1.end(),
vec2.begin(), vec2.end(),
std::back_inserter(result));
// Результат: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} (только если исходные отсортированы!)
Что не стоит делать
- Не используйте
std::copyсstd::back_inserterбезreserve— это работает, но может быть медленнее из-за переаллокаций. - Избегайте циклов с
push_back— это менее читаемо и не использует преимущества итераторов.
В современном C++ (C++17 и C++20) этот подход остаётся стандартом. Для пользовательских типов убедитесь, что у них есть корректный конструктор копирования.
<<Использование std::move для эффективного перемещения (C++11)
Если исходные векторы больше не нужны, и вы хотите избежать копирования элементов (особенно для больших объектов), используйте семантику перемещения:
#include <vector>
#include <utility> // для std::move
int main() {
std::vector<std::string> vec1 = {"apple", "banana"};
std::vector<std::string> vec2 = {"cherry", "date"};
std::vector<std::string> result;
result.reserve(vec1.size() + vec2.size());
// Перемещаем элементы из vec1 (vec1 становится пустым)
result.insert(result.end(),
std::make_move_iterator(vec1.begin()),
std::make_move_iterator(vec1.end()));
// Перемещаем элементы из vec2 (vec2 становится пустым)
result.insert(result.end(),
std::make_move_iterator(vec2.begin()),
std::make_move_iterator(vec2.end()));
// vec1 и vec2 теперь в "valid but unspecified" состоянии
return 0;
}
Важно: После перемещения исходные векторы остаются в корректном, но неопределённом состоянии (обычно пустые). Используйте этот метод только если вам больше не нужны исходные данные.
Дополнительный совет: concatenation с помощью std::vector::swap
Если вы хотите добавить элементы из одного вектора в конец другого (изменяя один из них), можно использовать swap с временным вектором:
std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2 = {4, 5, 6};
// Добавляем vec2 в конец vec1
vec1.insert(vec1.end(), vec2.begin(), vec2.end());
// vec1 = {1, 2, 3, 4, 5, 6}, vec2 не изменился
Этот подход изменяет один из исходных векторов, но не требует создания третьего вектора, что экономит память.
Ответов пока нет.
Войдите чтобы оставить ответ