最稳妥的vector合并方式是insert:v1.insert(v1.end(), v2.begin(), v2.end()),需注意参数顺序、类型一致、预分配内存;移动插入用std::make_move_iterator;已排序时优先std::merge;勿用+=或append。

用 insert 合并 vector,最常用也最容易出错
直接在目标 vector 末尾追加另一个 vector 的所有元素,insert 是最稳妥的选择。它不依赖移动语义,兼容 C++11 及以上,且不会意外改变原容器的容量策略。
常见错误是写成 v1.insert(v2.begin(), v2.end()) —— 参数顺序反了,编译不过;或者误用 push_back 想一次塞整个 vector,结果调用的是拷贝构造,编译报错:no matching member function for call to 'push_back'。
-
v1.insert(v1.end(), v2.begin(), v2.end()):正确,插入到末尾 - 如果想插在开头:
v1.insert(v1.begin(), v2.begin(), v2.end()) - 插入前建议
v1.reserve(v1.size() + v2.size()),避免多次内存重分配 - 注意:
v2必须和v1元素类型一致,否则编译失败
用 std::move + insert 避免深拷贝(C++11+)
当确定 v2 后续不再使用时,可以用移动迭代器把元素“搬”过去,省掉复制开销。但这不是万能优化——对 int、double 这类 trivial 类型,移动和拷贝没区别;对 std::string、自定义类等含堆内存的类型才真正受益。
容易踩的坑是只写 std::move(v2) 就以为完事了,其实 std::move 只转换为右值引用,真正起作用的是配合移动迭代器的 std::make_move_iterator。
立即学习“C++免费学习笔记(深入)”;
- 正确写法:
v1.insert(v1.end(), std::make_move_iterator(v2.begin()), std::make_move_iterator(v2.end())) - 执行后
v2处于有效但未定义状态(比如v2.size()可能为 0,也可能非 0,不能假设) - 别对
const vector或只读视图调用这个,编译不过
用 std::merge 合并两个已排序 vector
如果两个 vector 本身都已升序(或同为降序),用 std::merge 不仅合并,还保持整体有序,比先 insert 再 sort 快得多 —— 时间复杂度 O(n+m),而后者是 O((n+m) log(n+m))。
典型错误是忽略输出容器的空间准备:传入一个空 vector 却没 resize 或 reserve,导致 merge 写入越界或什么也不发生(因为用的是 back_inserter 才会自动 push,但性能差)。
- 推荐做法:
result.resize(v1.size() + v2.size()); std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin()) - 必须确保两个输入容器按同一规则排序,否则结果无序且不可预测
- 如果只要去重合并,
std::set_union更合适,但它要求输入已排序且去重
别用 += 或 append —— C++ vector 没这语法
有人从 Python 或 JS 切过来,下意识写 v1 += v2 或 v1.append(v2),C++ 标准库的 vector 完全不支持。编译器报错通常是:invalid operands to binary expression ('std::vector<int>' and 'std::vector<int>')</int></int> 或 no member named 'append' in 'std::vector<int>'</int>。
这不是编译器版本问题,也不是缺头文件,而是语言设计如此。标准库没提供这类操作符重载或成员函数,强行封装也要自己写,没必要。
- 坚持用
insert,清晰、标准、无歧义 - 如果高频合并,可封装一个内联辅助函数,但别为了语法糖牺牲可读性
- 第三方库如 Boost.Range 提供
join,但引入依赖得不偿失,除非项目已重度使用 Boost
实际写的时候,90% 场景用第一种 insert 就够了;真正要优化性能时,才需要判断是否可移动、是否已排序。类型匹配和内存预分配这两个点,比选哪个函数更容易被忽略。








