外观
lambda表达式捕获列表?
⭐ 题目日期:
金山 - 2024/12/31
📝 题解:
C++中的lambda表达式捕获列表允许访问外部作用域的变量,其使用方式及注意事项如下:
捕获列表的主要方式
显式捕获
[var]
:按值捕获变量var
。[&var]
:按引用捕获变量var
。
隐式捕获
[=]
:按值捕获所有外部变量。[&]
:按引用捕获所有外部变量。
混合捕获
[=, &var1, &var2]
:除var1
和var2
按引用捕获外,其他变量按值捕获。[&, var1, var2]
:除var1
和var2
按值捕获外,其他变量按引用捕获。
初始化捕获(C++14)
允许在捕获列表中定义新变量并初始化:[x = expr] // 用表达式expr的值初始化变量x(支持移动语义)。 auto lambda = [value = 10] { return value; }; // 直接定义新变量。
捕获
this
指针[this]
:捕获当前对象的指针,按引用访问成员变量。[*this]
(C++17):按值捕获当前对象的副本,避免悬空引用。
关键注意事项
修改捕获的变量
- 按值捕获的变量默认是
const
,需添加mutable
关键字才能修改:int x = 5; auto lambda = [x]() mutable { x += 1; }; // 修改的是副本。
- 按引用捕获可直接修改原变量,无需
mutable
。
- 按值捕获的变量默认是
生命周期管理
- 按引用捕获时,需确保变量在lambda执行时仍有效,否则导致悬空引用。
- 按值捕获或初始化捕获(如
[*this]
)可避免生命周期问题。
全局/静态变量
无需捕获,可直接访问:static int s = 10; auto lambda = [] { return s; }; // 无需捕获s。
避免隐式捕获的风险
隐式捕获(如[=]
或[&]
)可能导致意外捕获不需要的变量,建议显式指定关键变量。
示例代码
值捕获与引用捕获
int x = 10, y = 20; auto lambda1 = [x]() mutable { x += 5; }; // 修改副本x,原x仍为10。 auto lambda2 = [&y]() { y += 5; }; // 修改原变量y,y变为25。
混合捕获
int a = 1, b = 2, c = 3; auto lambda = [=, &b] { b = a + c; }; // a和c按值,b按引用。
初始化捕获(移动语义)
std::unique_ptr<int> ptr = std::make_unique<int>(42); auto lambda = [captured_ptr = std::move(ptr)] { std::cout << *captured_ptr; // ptr的资源已转移至captured_ptr。 };
捕获
this
与*this
class MyClass { int value = 100; public: void func() { auto lambda1 = [this] { value = 200; }; // 修改原对象的value。 auto lambda2 = [*this]() mutable { value = 200; // 修改的是副本的value。 }; } };
总结
- 按值捕获:安全,但需注意副本的修改(需
mutable
)。 - 按引用捕获:高效,但需谨慎生命周期。
- 初始化捕获(C++14):灵活,支持移动语义和复杂初始化。
- 混合捕获:结合显式与隐式捕获,灵活控制变量访问方式。
- 生命周期管理:引用捕获易引发悬空引用,按值或
[*this]
更安全。
合理选择捕获方式,避免悬空引用和性能问题,是编写健壮lambda表达式的关键。