std::for_each 默认传元素拷贝而非引用,故无法修改原容器值;需用[&](auto& x)显式引用捕获才能修改,const场景用const auto&更安全高效。

std::for_each 为什么改不了容器元素的值
默认情况下 std::for_each 传给函数对象的是元素的**拷贝**,不是引用,所以你在 Lambda 里改 x,原容器里的值根本不会变。
- 要修改原容器,必须显式用引用:
[&](auto& x) { x *= 2; } - 如果容器是
const或只读场景,用const auto&更安全、更高效 - 对
std::vector<bool></bool>这种特化类型,不能直接取引用(它返回 proxy 对象),得用std::vector<int></int>替代或改用传统 for 循环
std::for_each 和 range-based for 哪个该选
std::for_each 的核心价值不是“遍历”,而是把**算法意图显式表达出来**——你是在对每个元素做统一操作,而不是在写控制流。
- 需要提前退出(比如找到第一个满足条件的就停)?别用
std::for_each,它不支持中途 break,改用std::find_if或手写循环 - 要同时访问下标?
std::for_each不提供索引,得自己维护计数器或换std::enumerate(c++23)或用for (size_t i = 0; ...) - 性能上基本没差别,但
std::for_each可能因函数对象内联失败略慢一点;现代编译器通常优化得差不多
lambda 捕获方式写错导致崩溃或未定义行为
捕获不当是 std::for_each 最容易踩的坑,尤其涉及外部变量时。
- 想修改外部变量?必须用引用捕获:
[&sum](auto x) { sum += x; },否则[sum]是只读拷贝 - 捕获局部指针或引用后,容器生命周期结束还去访问?典型悬垂指针 —— 确保被遍历容器的生存期长于 lambda 执行期
- 多线程里用
std::for_each并发修改共享变量?它本身不加锁,必须手动同步,否则数据竞争
替代方案:什么时候不该硬套 std::for_each
它只是算法库中一个工具,不是银弹。很多看似“适合”的场景,其实有更清晰、更安全的选择。
立即学习“C++免费学习笔记(深入)”;
- 只读计算(求和、最大值等)?优先用
std::accumulate、std::max_element,语义明确且不易出错 - 需要过滤再处理?
std::for_each不筛选,组合std::copy_if+std::for_each反而更啰嗦,不如 range-v3 或 C++20 views - 逻辑分支多、状态复杂?强行塞进 lambda 会让代码难读,老老实实用传统 for 循环反而直白
真正关键的不是语法会不会写,而是每次调用前问一句:我到底是在“对每个元素执行动作”,还是在“实现某个具体业务逻辑”——后者往往不需要 std::for_each。