Avatar ·

Конкатенация двух std::vector в C++: как объединить векторы?

Всем привет! Я новичок в C++ и столкнулся с, казалось бы, простой задачей: мне нужно объединить два std::vector в один. Допустим, у меня есть два вектора целых чисел: ```cpp #include std::vector vec1 = {1, 2, 3}; std::vector vec2 = {4, 5, 6}; ``` Я хочу получить третий вектор `vec3`, который содержал бы элементы из обоих: `{1, 2, 3, 4, 5, 6}`. В Python я бы просто написал `vec3 = vec1 + vec2`, но в C++ оператор `+` для векторов не перегружен. Я попробовал сделать так: ```cpp std::vector vec3 = vec1 + vec2; // Ошибка компиляции ``` И получил ошибку. Потом я подумал использовать цикл `for`, но это кажется слишком громоздким и неэффективным. В интернете видел упоминания `std::merge`, `std::copy` и `insert`, но запутался в том, что лучше выбрать. Мне нужно простое и эффективное решение. Желательно, чтобы исходные векторы остались неизменными. Подскажите, как правильно объединить два вектора в C++? Какой способ считается наилучшей практикой в современном C++ (C++11 и новее)? Заранее спасибо! <<>>

Правильный способ: использование метода insert или алгоритмов std::copy/std::move

В C++ нет оператора + для std::vector, но есть несколько элегантных способов конкатенации. Самый простой и интуитивный — использовать метод insert у целевого вектора. Вот классическое решение:

#include <vector>
#include <iterator> // для std::back_inserter (опционально)

std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2 = {4, 5, 6};

// Способ 1: через insert (рекомендуется для новичков)
std::vector<int> vec3 = vec1;          // копируем первый вектор
vec3.insert(vec3.end(), vec2.begin(), vec2.end()); // вставляем второй в конец

// Результат: vec3 = {1, 2, 3, 4, 5, 6}

Этот код сначала создаёт копию vec1, а затем вставляет все элементы vec2 в конец. Метод insert принимает три аргумента: позицию (итератор на конец), начало и конец диапазона для вставки.

Альтернативный подход через std::copy с std::back_inserter

Если вы предпочитаете алгоритмы STL, можно использовать std::copy:

#include <algorithm> // для std::copy

std::vector<int> vec3;
vec3.reserve(vec1.size() + vec2.size()); // оптимизация: выделяем память заранее

vec3.insert(vec3.end(), vec1.begin(), vec1.end());
vec3.insert(vec3.end(), vec2.begin(), vec2.end());

// Или с std::copy:
// std::copy(vec1.begin(), vec1.end(), std::back_inserter(vec3));
// std::copy(vec2.begin(), vec2.end(), std::back_inserter(vec3));

Обратите внимание на вызов reserve. Он выделяет память сразу под итоговый размер, избегая многократных перераспределений. Это повышает производительность для больших векторов.

Современный C++17: std::merge для отсортированных векторов

Если оба вектора отсортированы, и вы хотите получить отсортированный результат, используйте std::merge:

#include <algorithm>

std::vector<int> vec1 = {1, 3, 5};
std::vector<int> vec2 = {2, 4, 6};
std::vector<int> vec3(vec1.size() + vec2.size());

std::merge(vec1.begin(), vec1.end(), 
           vec2.begin(), vec2.end(), 
           vec3.begin());
// vec3 = {1, 2, 3, 4, 5, 6}

std::merge требует предварительного выделения памяти (как в примере) и работает за линейное время O(n+m).

Что выбрать?

  • Если вам нужно просто объединить два вектора — используйте insert с reserve. Это читаемо и эффективно.
  • Если вы работаете с большими данными и хотите избежать копирования — используйте std::move (см. альтернативный ответ).
  • Если векторы отсортированы — std::merge даст отсортированный результат за один проход.

Главное — не пытайтесь перегрузить оператор + для векторов, это нарушит принципы работы стандартной библиотеки. Используйте готовые методы и алгоритмы STL — они оптимизированы и безопасны.

<<>>

Способ с перемещением (C++11 и новее)

Если исходные векторы больше не нужны, и вы хотите избежать лишних копирований, используйте семантику перемещения. Это особенно эффективно для больших объектов (например, std::vector<std::string>).

#include <vector>
#include <utility> // для std::move

std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2 = {4, 5, 6};

// Перемещаем vec2 в vec1 (vec2 станет пустым!)
vec1.insert(vec1.end(), 
            std::make_move_iterator(vec2.begin()), 
            std::make_move_iterator(vec2.end()));

// vec1 = {1, 2, 3, 4, 5, 6}
// vec2 теперь пуст или в неопределённом состоянии

Здесь std::make_move_iterator создаёт итератор, который при разыменовании использует std::move, что позволяет перемещать элементы вместо их копирования. После этой операции vec2 остаётся в "перемещённом" состоянии — его можно уничтожить или присвоить ему новое значение, но использовать его содержимое больше нельзя.

Важно: Этот способ подходит только если вам не нужны исходные данные. Для простых типов (int, double) выигрыша в производительности не будет, но для сложных объектов с динамическим выделением памяти (строки, контейнеры) перемещение может дать значительный прирост скорости.

Также можно полностью переместить второй вектор в первый, если он пуст:

std::vector<int> vec3 = std::move(vec1); // vec1 теперь пуст
vec3.insert(vec3.end(), vec2.begin(), vec2.end());

Выбирайте этот подход, когда память и производительность критичны, а исходные данные можно безопасно "уничтожить".