STL算法对容器迭代器有严格要求:find/find_if需前向迭代器,故不适用于unordered_set/map;sort需随机访问迭代器,list须用成员sort;copy/copy_if不检查目标空间,易越界;remove/remove_if需配合erase使用。

find 和 find_if 用错容器会直接编译失败
STL 的 find 和 find_if 只接受前向迭代器(forward iterator)及以上,但很多人在 std::list 或 std::vector 上用得顺手,就默认它们能在任何容器上跑——其实 std::unordered_set 和 std::map 不支持 find 算法(因为不提供连续/可递增的迭代器语义),必须用容器自身的 find() 成员函数。
常见错误现象:std::find(s.begin(), s.end(), x) 对 std::unordered_set 编译报错,提示 “no match for ‘operator!=’” 或迭代器类型不兼容。
-
std::find适用于所有支持==比较、且迭代器满足前向要求的容器(vector、list、deque、array) - 关联容器(
map、set)和哈希容器(unordered_map、unordered_set)应优先调用container.find(key),它平均 O(1) 或 O(log n),比算法遍历快得多 - 若硬要用算法查
unordered_set,得确保元素类型重载了operator==,且传入的是值而非键(它没“键值对”概念)
sort 要求随机访问迭代器,list 不能直接 std::sort
std::sort 内部依赖指针算术(如 it + n),只接受随机访问迭代器(RandomAccessIterator)。所以对 std::list 或 std::forward_list 直接调用 std::sort(l.begin(), l.end()) 会编译失败,不是运行时错,是模板实例化阶段就拒掉。
正确做法:
立即学习“C++免费学习笔记(深入)”;
- 对
std::list,用其成员函数l.sort()(稳定排序,基于归并) - 对
std::vector、std::deque、std::array,用std::sort最自然;注意它默认升序,用std::greater或 lambda 可改序() - 若需稳定排序(相等元素相对位置不变),别用
std::sort,改用std::stable_sort,它对vector也支持
示例:std::sort(v.begin(), v.end(), [](int a, int b) { return std::abs(a) —— 按绝对值升序,注意 lambda 捕获为空,避免意外引用外部变量。
copy 和 copy_if 容易写错目标迭代器长度,导致越界或静默截断
std::copy 和 std::copy_if 不检查目标空间大小,只按源范围长度写入。如果目标容器没预留足够空间(比如用 std::back_inserter 以外的迭代器),就会写到未分配内存,引发未定义行为。
典型踩坑场景:
- 目标是普通数组:
int dst[10]; std::copy(src.begin(), src.end(), dst);—— 若src.size() > 10,直接越界 - 目标是 vector 但没 resize:
std::vector——dst; std::copy(src.begin(), src.end(), dst.begin()); dst为空,dst.begin()是 end 迭代器,行为未定义 - 正确方式:用
std::back_inserter(dst)(自动 push_back),或提前dst.resize(src.size())再用dst.begin()
copy_if 同理,但更隐蔽:因为过滤后长度不确定,几乎必须用 back_inserter 或先计数再分配。
remove 和 remove_if 不真删元素,配合 erase 才算“删除”
std::remove 和 std::remove_if 是经典误解重灾区。它们不改变容器大小,只是把要删的元素“挪到末尾”,返回新逻辑结尾的迭代器。若忘了用 erase 清掉那段冗余数据,容器里依然躺着旧值,只是被覆盖逻辑上不可见。
标准写法(erase–remove 惯用法):
vec.erase(std::remove(vec.begin(), vec.end(), 0), vec.end()); // 删除所有 0
vec.erase(std::remove_if(vec.begin(), vec.end(), [](int x) { return x < 0; }), vec.end()); // 删除所有负数
注意点:
- 对
std::list,直接用l.remove(x)或l.remove_if(pred)更高效(链表原生支持) -
remove是不稳定操作:保留元素的相对顺序,但被移走的元素顺序不保证 - 不要对
std::vector频繁用 erase–remove 处理少量元素,考虑用std::partition+ 分段处理更优
最容易被忽略的是:这个惯用法只对序列容器有效;对 std::map 等,得用 erase 成员函数配循环或 C++20 的 erase_if。











