c++如何使用lambda表达式_c++匿名函数基本语法与应用【进阶】

9次阅读

c++ lambda 表达式语法为[捕获](参数)->返回类型{主体},捕获列表必写,参数括号不可省,返回类型可推导;常用于stl算法,需注意捕获方式与生命周期;每个Lambda类型唯一,跨作用域传递宜用std::function

c++如何使用lambda表达式_c++匿名函数基本语法与应用【进阶】

lambda 表达式的基本语法结构

c++ 中,[capture](parameters) -> return_type { body } 是完整 lambda 的骨架。方括号 [] 是捕获列表,必须有;圆括号 () 内的参数可空(此时可省略 void),但括号不能省;箭头 -> 和返回类型可省略(编译器自动推导),但一旦函数体含多条语句或返回类型不明确,就容易推导失败;花括号内是执行逻辑。

常见写法示例:

auto f1 = []() { return 42; };                    // 无参无捕获,返回 int auto f2 = [&](int x) { vec.push_back(x); };       // 按引用捕获外部变量,接受一个 int auto f3 = [val](double d) -> std::string { return std::to_string(val * d); }; // 值捕获 val,显式声明返回类型

注意:若只捕获部分变量,必须显式列出;[=][&] 是全量捕获,但会隐式忽略 this(类成员函数中需写 [this][=, this] 才能访问成员)。

在 STL 算法中传入 lambda 的典型用法

lambda 最常用于 std::sortstd::find_ifstd::transform 等算法的谓词参数。此时重点不是语法炫技,而是避免意外拷贝和生命周期问题。

立即学习C++免费学习笔记(深入)”;

  • std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; }); —— 安全,无捕获,纯函数式
  • std::find_if(data.begin(), data.end(), [target](const auto& item) { return item.id == target; }); —— 值捕获 target,确保 lambda 生命周期内 target 有效
  • 错误写法:[&target]target局部变量且 lambda 在函数返回后被调用(如存入容器、异步调度),就会引发悬垂引用

性能提示:简单比较逻辑尽量用值捕获或无捕获,避免引用捕获带来的 lifetime 约束;对大对象,考虑用 const& 参数而非值传递

lambda 作为函数对象存储与转发的限制

每个 lambda 表达式生成一个**唯一的、未命名的闭包类型**,即使两个 lambda 写法完全一样,类型也不同。这意味着:

  • 不能直接用 auto 以外的类型名声明多个相同逻辑的 lambda 变量(auto 是最安全选择)
  • 不能把 lambda 直接赋给 std::function 以外的普通函数指针(除非它不捕获——此时可隐式转为函数指针)
  • 想存起来反复用或跨作用域传递,优先用 std::function 包装,但要注意其有小对象优化(SBO)阈值,捕获内容过大时会有分配开销

例如:

std::function<bool(int)> pred = [](int x) { return x % 2 == 0; }; // OK bool (*fp)(int) = [](int x) { return x > 0; }; // OK:无捕获,可转函数指针 bool (*bad_fp)(int) = [&x](int y) { return y > x; }; // 编译错误:有捕获,无法转函数指针

在类成员函数中使用 lambda 访问 this 和成员变量

类内定义 lambda 时,默认不捕获 this,哪怕用了 [=][&]。这是 C++17 起明确规定的,目的是防止隐式延长对象生命周期。

正确做法只有两种:

  • 显式写 [this]:捕获 this 指针,可读写所有非静态成员(包括私有)
  • 显式写 [=, this][&, this]:同时按值/引用捕获外部变量 + 显式捕获 this

陷阱示例:

class Widget {     int value = 42;     void process() {         auto bad = [=]() { return value; };     // ❌ 编译错误:value 不在捕获列表中         auto good = [this]() { return value; }; // ✅ 正确         auto also_good = [=, this]() { return value + offset; }; // ✅ 同时捕获 this 和外部变量 offset     } };<p>如果 lambda 需要异步执行(比如交给线程或定时器),务必确认对象生命周期是否覆盖 lambda 执行期;否则 <code>[this]</code> 会导致悬垂指针。</p>

text=ZqhQzanResources