std::for_each是中的函数模板,用于对区间内每个元素调用指定可调用对象,不支持break/continue,仅依次调用且返回函数对象副本。

for_each 是函数模板,不是循环语句
std::for_each 是 头文件里的函数模板,作用是对区间内每个元素调用指定的函数对象(可调用物)。它不提供“遍历控制权”,也不支持提前跳出(除非抛异常),和 for 循环语义不同。
常见误用是把它当 for 写法的替代品来“控制流程”,结果发现不能 break、不能 continue、返回值无意义。它只做一件事:依次调用。
- 必须传入左闭右开区间:
begin和end迭代器(比如v.begin(),v.end()) - 第三个参数是可调用对象:可以是 lambda、函数指针、functor,但签名必须接受单个参数(元素类型或其引用)
- 对空容器安全,不会执行任何调用
lambda 捕获与引用陷阱
用 lambda 时最容易踩的是变量捕获方式错误。尤其修改外部变量或遍历容器本身时,[&] 和 [=] 行为差异极大。
例如想统计偶数个数:
立即学习“C++免费学习笔记(深入)”;
int count = 0;
std::for_each(v.begin(), v.end(), [&count](int x) { if (x % 2 == 0) ++count; });
这里必须用 [&count] 或 [&],用 [=] 会捕获 count 的副本,外部 count 不变。
- 若 lambda 修改容器元素,应捕获元素引用:
[](int& x) { x *= 2; } - 若只读,用
const int&更高效(避免拷贝大对象) - 在 range-based for 更清晰的场景(如简单修改、打印),别硬套
for_each
for_each 和 range-based for 的性能与可读性取舍
两者生成的汇编通常一致,编译器能很好优化。区别主要在表达意图和维护成本。
-
for_each更适合“把操作抽象成独立行为”的场景,比如复用同一个处理逻辑:for_each(a.begin(), a.end(), log_item)+for_each(b.begin(), b.end(), log_item) - range-based for 在需要索引、条件跳过、或混合操作(如“遇到 0 就停止”)时更直接;
for_each做不到自然中断 - 调试时,lambda 调用栈比 for 循环深一层,断点不易打到具体某次迭代
for_each 返回值常被忽略的用途
std::for_each 返回传入的函数对象(按值返回),不是 void。这个特性极少用,但可用于链式调用或检查状态(比如 functor 内部计数)。
例如:
struct Counter {
int n = 0;
void operator()(int) { ++n; }
};
Counter c = std::for_each(v.begin(), v.end(), Counter{});
// 此时 c.n 是容器大小(前提是没提前退出)
注意:返回的是副本,原对象状态未保留;若 functor 有状态且需后续访问,应传入左值引用或改用其他方式。
真正需要这种写法的场景极少见,多数时候只是白添复杂度。别为了“用 STL”而用 for_each —— 容器是否支持随机访问、操作是否纯、是否要异常安全,这些才决定该不该选它。








