std::for_each可遍历修改原生数组,需用std::begin/std::end避免越界;std::transform适用于映射生成新数组,就地变换需确保lambda不依赖旧值;lambda捕获局部变量时须注意悬垂引用。

用 std::for_each 遍历并修改数组元素
直接在原生数组上用 std::for_each 是可行的,但必须传入指针范围,不能只传数组名——因为数组名会退化为指针,丢失长度信息,容易越界或漏处理。
常见错误是写成 std::for_each(arr, arr + 5, [](int& x) { x *= 2; }); 看似正确,但若数组大小变化而没同步改 5,就出问题。更安全的做法是配合 std::size(C++17 起):
int arr[] = {1, 2, 3, 4, 5};
std::for_each(std::begin(arr), std::end(arr), [](int& x) {
x += 10;
});
-
std::begin/std::end能正确推导原生数组长度,比手算arr + N更可靠 - Lambda 捕获为空,参数用
int&才能修改原数组值;若用int x就只是副本操作 - 注意:
std::for_each不保证执行顺序,但对普通数组遍历无影响;若逻辑依赖顺序(如累加),应改用for循环或std::accumulate
用 std::transform 实现数组映射(比如平方、转字符串)
当需要把一个数组转换成另一个同长数组(或容器)时,std::transform 比手写循环更清晰,也天然适配 Lambda。
例如把 int 数组转成 double 平方值:
int src[] = {1, 2, 3};
double dst[3];
std::transform(std::begin(src), std::end(src), dst,
[](int x) { return static_cast<double>(x * x); });</double>
- 第三个参数是目标起始地址,必须确保空间足够,否则写越界——
dst长度没检查,靠程序员保证 - 如果目标也是原生数组,不能用
std::back_inserter;它只适用于支持push_back的容器(如std::vector) - 若想就地变换(输入输出同一数组),让第三个参数也用
std::begin(src)即可,但需确认 Lambda 不依赖未更新的旧值
捕获外部变量时要注意生命周期和 const 语义
Lambda 捕获局部数组或栈变量时,若 Lambda 存活时间超过变量作用域,就会悬垂——这是运行时崩溃的常见原因。
比如在函数内定义数组,又把 Lambda 存进 std::function 或线程里:
std::function<void> make_bad_lam() {
int local_arr[] = {1, 2, 3};
return [&]() { std::cout <ul>
<li>用 <code>[&]</code> 捕获引用,但 <code>local_arr</code> 是栈对象,函数返回后内存失效</li>
<li>改用 <code>[=]</code> 也不行——原生数组不能被值捕获(编译报错:<code>error: array type 'int [3]' is not assignable</code>)</li>
<li>安全做法:把数组包进 <code>std::array</code> 或 <code>std::vector</code>,再用 <code>[=]</code> 捕获,它们支持拷贝</li>
<li>或者明确传参,不依赖捕获:把数组首尾指针作为参数传给 Lambda 调用点</li>
</ul>
<h3>性能提示:原生数组 + Lambda 不一定比传统 for 快</h3>
<p>很多人默认“STL + Lambda 更现代,所以更快”,实际未必。编译器对简单 <code>for</code> 循环的优化(如向量化、循环展开)往往比对 <code>std::for_each</code> 内联更激进。</p>
<ul>
<li>用 <code>-O2</code> 编译时,两者生成的汇编常一致;但若 Lambda 体复杂或含条件分支,<code>std::for_each</code> 可能多一层函数调用开销(虽然通常被内联)</li>
<li>真正影响性能的是访问模式:连续内存 + 无别名(<code>int*</code>)最友好;若 Lambda 中混用全局指针或 <code>std::vector::data()</code>,可能阻碍向量化</li>
<li>调试时,Lambda 堆栈帧不如裸 <code>for</code> 直观——GDB 展开 <code>std::for_each</code> 调用链略深,定位具体哪次迭代出错稍慢</li>
</ul>
<p>原生数组本身不带边界检查,所有 Lambda 操作都建立在“你已确保指针合法”的前提上——这点最容易被忽略,也是线上 core dump 的高频源头。</p></void>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











