std::for_each不能直接安全修改容器元素,因其默认传递值拷贝或const引用;需用非const引用参数(如[](int& x))才能修改原元素,但vector等特例除外,此时应改用transform或传统循环。

std::for_each 不能直接修改容器元素?
不能——至少不是安全地、按你直觉想的那样改。因为 std::for_each 默认传入的是元素的**值拷贝**或**const 引用**,你在 lambda 里对形参赋值,根本不会影响原容器。常见错误是这么写:
std::vector<int> v = {1, 2, 3};
std::for_each(v.begin(), v.end(), [](int x) { x *= 2; }); // 没用!v 还是 {1,2,3}
</int>
原因很简单:lambda 参数 x 是 int 值类型,进函数就复制一份,改它等于白改。
要改元素,必须传引用
得让 lambda 接收元素的**非 const 引用**,这样修改才作用到原位置。关键在参数声明:
- 写成
[](int& x)(推荐):可读、安全、明确意图 - 别写成
[](auto x):自动推导仍是值类型,照样无效 - 可以写
[](auto& x),但要注意v.end()不是合法引用目标,不过for_each内部不解引用 end,所以实际可用
正确示例:
std::vector<int> v = {1, 2, 3};
std::for_each(v.begin(), v.end(), [](int& x) { x *= 2; }); // v 变成 {2,4,6}
</int>
为什么不用 std::transform?
如果你只是做“逐个映射”,std::transform 更语义清晰、更常用,而且天然支持就地变换(in-place):
std::transform(v.begin(), v.end(), v.begin(), [](int x) { return x * 2; });
对比 for_each:
- for_each 语义是「执行副作用」,比如打印、更新外部状态;
- transform 语义是「生成新值」,哪怕目标迭代器和源相同,也明确表达「我打算改它」。
所以除非你要在遍历时同时做其他事(比如计数 + 修改),否则优先选 transform。
vector 是个特例,千万别用 for_each 改
std::vector<bool></bool> 不是真正的容器,它的 operator[] 返回的是代理对象(std::vector<bool>::reference</bool>),不是 bool&。这时即使你写 [](bool& x),编译都过不去:
std::vector<bool> b = {true, false};
std::for_each(b.begin(), b.end(), [](bool& x) { x = true; }); // ❌ 编译错误:cannot bind non-const lvalue reference to an rvalue
</bool>
解决办法只有两个:
- 改用 std::vector<char></char> 替代(最稳妥)
- 或用传统 for 循环 + at()/operator[](它们返回可修改的代理)
真正容易被忽略的是:for_each 的设计本意不是为了修改,而是为了“执行动作”。一旦你发现自己总在 lambda 里写赋值,该停下来想想——是不是该换 transform、范围 for,或者干脆承认这是个算法误用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











