外观
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与*thisclass 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表达式的关键。
