std::set_union要求输入为已排序区间,输出需可写容器;常用vector配合back_inserter高效获取有序去重结果,或用inserter写入新set;不可用set迭代器作输出,自定义类型须保证比较一致。

set_union 要求输入是已排序的范围,而 set 本身有序,但不能直接传迭代器进去就完事
因为 std::set_union 是泛型算法,它不认 std::set 类型,只认「支持前向迭代器的、已排序的区间」。你得把两个 set 的迭代器传给它,再提供一个输出容器(比如 std::vector 或另一个 std::set)来接收结果。
常见错误是直接写 set_union(a.begin(), a.end(), b.begin(), b.end(), a.begin()) —— 这会越界或写入只读位置,set 的迭代器是 const 的,不能用作输出迭代器。
- 输出目标必须是可写容器,例如
std::vector<int>或用std::inserter包装的std::set - 输入迭代器没问题:
set::begin()和set::end()满足严格弱序要求 - 别忘了包含头文件:
<algorithm>和<set>(以及<iterator>如果用inserter)
用 vector 接收并集结果最简单,也最常用
这是性能和可读性兼顾的做法:不用额外构造 set,避免重复插入开销;结果天然去重且有序,符合并集语义。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
std::set<int> a = {1, 2, 4};
std::set<int> b = {2, 3, 4, 5};
std::vector<int> result;
result.reserve(a.size() + b.size()); // 预留空间防多次 realloc
std::set_union(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(result));
-
std::back_inserter(result)把每次写入转为push_back,安全高效 -
reserve不是必须,但对大集合能明显减少内存重分配 - 结果
result是{1,2,3,4,5},保持升序,无重复
想原地合并进一个 set?用 inserter 包装,别手写循环
有人试图遍历 b 并对每个元素调 a.insert(x),这虽然可行,但时间复杂度是 O(m log n),不如 set_union 的线性合并 O(n+m)。
立即学习“C++免费学习笔记(深入)”;
std::set<int> a = {1, 2, 4};
std::set<int> b = {2, 3, 4, 5};
std::set<int> result;
std::set_union(a.begin(), a.end(), b.begin(), b.end(), std::inserter(result, result.begin()));
-
std::inserter(result, result.begin())的第二个参数只是占位,inserter内部会自动用insert方法,与插入位置无关 - 注意:不要传
a.begin()试图“原地更新 a”——set迭代器不可写,编译不过 - 如果真要覆盖
a,只能先清空再 insert:a.clear(); std::set_union(..., std::inserter(a, a.begin()));
自定义类型要用 operator< 或提供 Compare,否则 set_union 编译失败
如果你的 set 存的是结构体,比如 std::set<Point>,那不仅 set 构造时要能比较,set_union 内部也要用同一套序关系 —— 它默认调用 operator<。
- 没定义
operator<?编译报错:「invalid operands to binary expression」或类似提示 - 用了自定义
Compare(如std::set<int, std::greater<int>>),那两个输入set的比较器必须相同,否则行为未定义 - 若比较逻辑复杂,建议统一用函数对象传给
set_union第五个参数,显式保持一致:std::set_union(..., cmp)
back_inserter 还是 inserter。

















