std::merge要求两输入序列各自有序,输出到第三容器;参数顺序为(first1,last1,first2,last2,result),目标空间需预先分配,不支持list/forward_list默认版本,自定义比较函数需符合严格弱序,大对象合并应确保移动构造函数noexcept。

std::merge 用法和基本约束
它不是万能的“合并数组”函数,而是严格要求两个输入序列必须各自有序,输出到第三个容器(或迭代器范围)里。你传进去乱序数据,结果不会报错,但结果肯定不对——这是最常踩的坑。
-
std::merge不排序,只归并;想合并再排序,得先std::sort再std::merge - 三个迭代器参数顺序固定:
merge(first1, last1, first2, last2, result),漏掉last2或颠倒first2/last2位置会导致编译失败或越界 - 输出目标(
result)必须有足够空间,std::merge不分配内存,也不检查容量——写到std::vector末尾前记得reserve或用back_inserter
常见错误:段错误或输出截断
典型现象是程序崩溃、输出少一半元素,或者最后几个值全是零/随机值。根本原因几乎都是输出缓冲区没预留够空间,或者用了已失效的迭代器。
- 用
std::vector接收时,别直接传v.begin()——如果v.size() == 0,begin() == end(),merge会往空地写 - 正确做法之一:
v.resize(len1 + len2); std::merge(a.begin(), a.end(), b.begin(), b.end(), v.begin()); - 更安全的做法:
std::vector<int> out; out.reserve(a.size() + b.size()); std::merge(..., std::back_inserter(out));</int> - 别对
std::list或std::forward_list用std::merge默认版本——它们不支持随机访问,但标准库提供了针对list::merge成员函数,行为不同,别混用
自定义比较逻辑怎么传
默认按 比较,但实际中经常要升序合并字符串、降序合并数字,或者按结构体字段比。关键点是:比较函数必须满足严格弱序,且签名必须是 <code>bool( const T&, const T& )。
- lambda 最常用:
std::merge(a.begin(), a.end(), b.begin(), b.end(), out.begin(), [](int x, int y) { return x > y; }); // 降序合并 - 注意:这个 lambda 是判断“第一个参数是否应该排在第二个参数前面”,不是“是否相等”或“是否小于等于”
- 如果用函数指针,确保声明为
bool cmp(const X&, const X&),不能带std::命名空间前缀(如std::less是模板,不是可传入的函数对象) - 用
std::greater<int>()</int>比手写 lambda 更轻量,但类型必须显式:std::merge(..., std::greater<int>())</int>
性能与移动语义注意事项
如果你合并的是大对象(比如 std::string 或自定义类),默认拷贝可能成为瓶颈。C++11 起 std::merge 支持移动,但前提是你的比较函数不干扰移动,且目标容器支持移动插入。
立即学习“C++免费学习笔记(深入)”;
- 输出用
std::move_iterator包装输入,可以触发移动:std::merge(std::make_move_iterator(a.begin()), ...) - 但注意:源容器(
a,b)在 merge 后处于有效但未指定状态——别再读它们的元素 - 内置类型(
int,double)无所谓移动拷贝,但自定义类型务必确认移动构造函数是noexcept,否则某些标准库实现会退回到拷贝 - 如果只是合并
int数组,不用操心移动;但如果合并的是含堆内存的类,漏掉noexcept可能导致静默降级为深拷贝
std::merge 就会安静地给你一个错得离谱的结果。








