copy_if是C++中不修改原容器、仅按谓词条件复制元素到目标区间的算法;需确保目标空间足够或使用back_inserter,与remove_if的本质区别在于是否就地修改。

copy_if 是 C++ 标准库中真正按条件做“过滤式复制”的函数,它不修改原容器,只把满足谓词的元素拷贝到目标区间——这是它和 remove_if 最本质的区别。
copy_if 的基本用法和参数含义
它定义在 头文件里,签名是:
templateOutputIt copy_if(InputIt first, InputIt last, OutputIt d_first, UnaryPredicate pred);
关键点:
-
first和last是输入范围的迭代器(左闭右开),不能是单个值 -
d_first是输出起始位置,必须保证目标空间足够大;它不会自动扩容,也不会构造新容器 -
pred是一元谓词,返回bool;传入的是解引用后的元素值(比如*it),不是迭代器本身 - 返回值是输出区间的末尾迭代器(即最后一个被写入位置的下一个),方便链式操作或后续处理
常见错误:目标容器没预留空间 or 迭代器类型不匹配
最常踩的坑是直接往空 vector 里用 back_inserter 却忘了初始化容量,或者误用 begin() 而非 back_inserter():
立即学习“C++免费学习笔记(深入)”;
- ❌ 错误写法:
vector——out; copy_if(in.begin(), in.end(), out.begin(), [](int x){return x>0;}); out是空的,out.begin()等价于out.end(),写入越界 - ✅ 正确之一(预分配):
vectorout(in.size()); auto it = copy_if(in.begin(), in.end(), out.begin(), [](int x){return x>0;}); out.resize(distance(out.begin(), it)); - ✅ 正确之二(动态追加):
vectorout; copy_if(in.begin(), in.end(), back_inserter(out), [](int x){return x>0;}); - ⚠️ 注意:
back_inserter返回的是插入迭代器,底层调用push_back,有潜在 realloc 开销;而预分配 + 普通迭代器写入是纯 O(n) 无额外分配
和 remove_if / erase-remove 惯用法的本质区别
很多人混淆 copy_if 和 remove_if,核心在于“是否就地修改”:
-
copy_if:读取源区间,写入另一块内存,原容器完全不变 -
remove_if:重排原容器内元素,把满足条件的“挪到后面”,返回新逻辑结尾;必须配合erase才算真正删除(即 erase-remove 惯用法) - 性能上:
copy_if需要额外空间,但稳定;remove_if原地、省空间,但会改变原顺序(相对顺序保留,但位置偏移) - 适用场景:
copy_if更适合“生成新结果”(比如日志筛选、数据导出);remove_if更适合“清洗当前数据”(比如剔除无效缓存项)
真正容易被忽略的是谓词捕获的生命周期问题——如果用 lambda 捕获了局部容器的引用,又把 copy_if 用在异步任务里,就可能访问已销毁对象。这种 bug 不报错,但行为未定义。










