std::unique_copy只移除相邻重复元素,不进行全局去重;需先排序才能得到唯一元素集,且要求目标空间足够、迭代器合法、元素支持相等比较。

std::unique_copy 为什么不能直接去重所有重复元素
std::unique_copy 只移除「相邻重复」,不是全局去重。它不改变原容器顺序,也不做哈希或查找,只从前到后扫一遍,把和前一个元素相等的当前元素跳过。如果你的输入是 {1,2,2,3,1,1},输出是 {1,2,3,1},而不是 {1,2,3} —— 后者得先排序再用 std::unique_copy,或者换 std::set。
正确调用 std::unique_copy 的三个必要条件
它是个算法,不操作容器本身,只拷贝“去重后”的结果到目标区间,所以必须确保目标空间足够大,且传入合法迭代器范围:
- 源范围必须是有效的左闭右开区间,比如
v.begin()到v.end() - 目标起始迭代器指向的空间至少要有
std::distance(first, last)个可写位置(哪怕实际只写入更少) - 元素必须支持
operator==,或你提供自定义二元谓词(如std::equal_to<>()或 lambda)
常见错误是目标 vector 没预留空间,导致越界写入或未定义行为:
std::vector<int> src = {1,1,2,2,2,3};
std::vector<int> dst;
std::unique_copy(src.begin(), src.end(), dst.begin()); // ❌ dst.empty(),dst.begin() 是 end 迭代器
怎么安全地把结果存进 vector
最常用也最稳妥的方式是先用 std::unique 预估长度,再用 reserve + back_inserter:
立即学习“C++免费学习笔记(深入)”;
std::vector<int> src = {1,1,2,2,3,3,3};
std::vector<int> dst;
dst.reserve(src.size()); // 避免多次 realloc
std::unique_copy(src.begin(), src.end(), std::back_inserter(dst));
也可以用 resize 配合返回的迭代器(std::unique_copy 返回目标末尾):
std::vector<int> dst(src.size()); auto it = std::unique_copy(src.begin(), src.end(), dst.begin()); dst.resize(std::distance(dst.begin(), it));
注意:如果用 std::array 或裸数组作目标,必须手动保证长度够;用 std::copy_n 类接口时尤其容易溢出。
自定义比较逻辑时的典型陷阱
比如按绝对值去重:{-2,2,3,-3} → {-2,3}。必须传入二元谓词,且它要满足「等价关系」:自反、对称、传递。否则行为未定义:
- ✅ 正确写法:
[](int a, int b) { return std::abs(a) == std::abs(b); } - ❌ 错误写法:
[](int a, int b) { return a == -b; }(不满足自反性:f(2,2)返回 false) - ⚠️ 注意:谓词参数顺序是
(*(i-1), *i),即“前一个”和“当前”,别反了
另外,谓词不能修改参数,也不能抛异常(除非你明确处理)。
C++ 标准库没提供“带状态”的去重算法,所以如果要去重逻辑依赖上下文(比如只跳过连续两个以上重复),就得手写循环 ——std::unique_copy 的契约非常窄,但正因如此才快且可预测。


















