std::for_each配合非const引用lambda可安全条件修改容器元素,但需注意vector特化不支持引用修改,原生数组需用std::begin/end,多维数组宜展平处理。

用 std::for_each 配合 lambda 实现条件批量修改
直接遍历改值最直观,但容易写错边界或漏判条件。用 std::for_each 能把“遍历”和“逻辑”分离,避免手写 for 循环时下标越界或迭代器失效。
常见错误是把条件判断写在循环外,导致全量修改;或者在 lambda 里误用 const 引用,编译报错 assignment of read-only reference。
- lambda 参数必须用非 const 引用:
[&](int& x) { if (x > 10) x *= 2; } - 容器必须支持随机访问或前向迭代(
std::array、std::vector、原生数组转std::span均可) - 原生 C 风格数组需配合
std::begin/std::end:std::for_each(std::begin(arr), std::end(arr), [](int& x) { ... });
原生数组用 std::transform 更适合“映射式”批量更新
当修改逻辑是纯函数式(输入元素 → 输出新值),std::transform 比 for_each 更贴切,语义清晰且天然支持就地更新(传入相同起始迭代器)。
容易忽略的是:如果目标区间和源区间重叠,又没用就地模式(即第三个参数不是 begin),会意外覆盖未处理元素。
- 就地更新写法:
std::transform(arr, arr + N, arr, [](int x) { return x % 2 == 0 ? x * 3 : x; }); - 不支持原生数组长度自动推导,
N必须显式传入,宏定义sizeof(arr)/sizeof(*arr)在函数参数中会退化为指针,不可用 - 若需保留原数组,第三个参数应指向另一块内存,否则行为未定义
性能敏感场景慎用 std::vector<bool></bool>
它不是真正的容器,而是位压缩特化,operator[] 返回代理对象而非引用,导致 for_each 或 transform 中的 lambda 无法通过引用修改——编译可能通过,但运行时无效或崩溃。
- 遇到条件修改
vector<bool></bool>元素,必须改用std::vector<char></char>或std::deque<bool></bool> - 哪怕只改一个
true→false,也得走完整迭代,不能靠短路 - Clang 和 GCC 对该特化的实现细节不同,跨平台时尤其容易踩坑
多维数组条件修改要先展平索引逻辑
C++ 没有内置多维容器,std::array<:array>, 3></:array> 或 std::vector<:vector>></:vector> 的嵌套结构会让条件判断分散在内外层循环里,难维护也难复用。
更可靠的做法是用单层循环加坐标换算,或封装成带坐标的 lambda。
- 展平访问示例(二维):
for (int i = 0; i - 用
std::span(C++20)可把二维视作一维:std::span<int> flat(data[0], rows * cols); std::for_each(flat.begin(), flat.end(), [](int& x) { ... });</int> -
vector<vector>></vector>无法保证内存连续,不能安全展平;必须逐行处理或改用vector<int></int>+ 手动索引
实际批量改值时,最常被跳过的是确认容器类型是否支持就地修改、以及是否隐含别名问题(比如 vector<bool></bool>)。一旦数据规模上去,这些底层表现会直接变成 bug 而不是性能问题。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











