std::copy_if是最直接的条件筛选方式,不修改原容器、语义清晰;常见错误是目标迭代器未预留空间或重叠,需用back_inserter或预分配空间,谓词捕获注意生命周期,就地过滤应选remove_if+erase。

std::copy_if 是最直接的实现方式
不用手写循环,std::copy_if 就是标准库为这类需求准备的工具。它把满足谓词的元素复制到目标区间,不修改原数组,语义清晰、无副作用。
常见错误是传错目标迭代器:比如用 std::back_inserter 时忘了提前预留空间,或直接用原数组起始地址导致越界写入。
- 源容器和目标容器不能重叠(除非用
std::remove_copy_if配合 erase-erase 惯用法) - 目标容器需有足够空间,或使用支持动态增长的容器 +
std::back_inserter - 谓词可为 lambda、函数指针或函数对象,捕获变量时注意生命周期
std::vector<int> src = {1, 2, 3, 4, 5, 6};
std::vector<int> dst;
dst.reserve(src.size()); // 避免多次 realloc
std::copy_if(src.begin(), src.end(), dst.begin(),
[](int x) { return x % 2 == 0; }); // 保留偶数
</int></int>
就地过滤要用 std::remove_if + erase 组合
如果必须复用原数组内存、不额外分配空间,std::remove_if 是唯一安全的就地方案。它不真正删除元素,而是把不满足谓词的元素“推到末尾”,返回新逻辑结尾——必须配合 erase 才能缩容。
漏掉 erase 是高频错误,会导致容器 size 不变、尾部残留无效数据;反过来,对普通数组(非容器)不能用 erase,得自己记录新长度。
-
std::remove_if是稳定算法,相对顺序不变 - 对
std::array或裸数组,只能用返回的“新尾迭代器”标记有效范围,无法自动缩容 - 谓词为
true表示“要移除”,逻辑容易反,建议注释清楚
std::vector<int> v = {1, 2, 3, 4, 5};
v.erase(std::remove_if(v.begin(), v.end(),
[](int x) { return x
<h3>原始数组(int arr[])怎么处理</h3>
<p>没有容器接口,就不能直接用 <code>std::copy_if</code> 写入原数组——会覆盖后续元素。正确做法是用两个指针手动遍历,或借助 <code>std::partition</code>(如果允许重排)。</p>
<p>最容易踩的坑是边界判断出错:比如循环条件写成 <code>i 导致访问越界,或新长度没保存下来,调用方仍按原长度使用。</code></p>
<ul>
<li>返回新长度比修改原数组更安全,调用方决定是否 memcpy 或截断</li>
<li>若需保序且不能扩容,只能 O(n) 扫描两遍:第一遍计数,第二遍复制</li>
<li>
<code>std::partition</code> 效率高但打乱顺序,仅适用于“只要结果集、不要原始次序”的场景</li>
</ul>
<pre class="brush:php;toolbar:false;">int arr[] = {1, 2, 3, 4, 5};
int len = 5;
int write_idx = 0;
for (int i = 0; i
<h3>性能与谓词开销需要注意什么</h3>
<p>谓词本身不该有副作用,也不该做重操作(如文件读写、锁竞争)。编译器通常能内联简单 lambda,但若谓词调用虚函数或通过函数指针传入,可能阻碍优化。</p>
<p>对超大数组,缓存友好性比算法复杂度更关键:<code>std::copy_if</code> 是单向扫描,局部性好;而 <code>std::remove_if</code> 在某些实现中会有两次遍历(一次找、一次搬),但实际差异极小。</p>
- 避免在谓词里做动态内存分配(如构造
std::string) - 若谓词逻辑复杂且被频繁调用,考虑提前计算并缓存中间结果
- 对
std::vector<bool></bool>这种特化容器,std::copy_if可能因位操作产生意外行为,建议换用std::vector<char></char>
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











