Lambda表达式是 C++11 引入的一种匿名函数,允许在需要函数对象的地方直接定义一个函数,无需显式定义函数名。Lambda 表达式常用于实现回调函数、临时函数、算法函数等场景。

基本语法

Lambda 表达式的完整语法结构如下:

[ captures ] ( params ) mutable -> return_type { body }
组成部分 说明
[ captures ] 捕获列表,定义外部变量如何被 Lambda 访问(值捕获、引用捕获等)
( params ) 参数列表,与普通函数参数列表一致
mutable 可选关键字,允许修改按值捕获的变量
-> return_type 可选返回类型,可省略(编译器自动推导)
{ body } Lambda 函数体

捕获列表(Capture List)

捕获方式

捕获方式 语法示例 行为
​按值捕获 [x] 复制外部变量 x 的值到 Lambda 内部
​按引用捕获 [&x] 直接引用外部变量 x
​隐式按值捕获全部 [=] 按值捕获所有外部变量(不推荐,易导致悬空引用或性能问题)
​隐式按引用捕获全部 [&] 按引用捕获所有外部变量(不推荐,需谨慎管理生命周期)
​混合捕获 [x, &y] 按值捕获 x,按引用捕获 y
​初始化捕获(C++14+) [z = x + 1] 创建新变量 z,其值为 x + 1(可用于移动语义或复杂初始化)

示例代码

int a = 1, b = 2;

// 按值捕获 a,按引用捕获 b
auto lambda1 = [a, &b]() { return a + b; };

// 隐式按引用捕获所有外部变量
auto lambda2 = [&]() { a++; b++; };

// 初始化捕获(C++14+)
auto lambda3 = [c = a * 2]() { return c; }; // c = 2

参数列表(Parameters)

  • 与普通函数参数列表一致,支持值传递、引用传递、默认参数等。
  • ​无参数时可省略:[] { ... }
    示例
auto add = [](int x, int y) { return x + y; }; // 值传递
auto print = [](const std::string& s) { std::cout << s; }; // 引用传递
auto no_args = [] { return 42; }; // 无参数

mutable 关键字

  • 默认情况下,按值捕获的变量在 Lambda 内部是 ​不可修改 的。
  • 使用 mutable 后,可以修改按值捕获的变量(修改的是副本,不影响外部变量)。
    示例
int count = 0;

auto increment = [count]() mutable {
    count++; // 允许修改按值捕获的 count(副本)
};

increment(); // 外部 count 仍为 0

返回类型(Return Type)

  • 返回类型可省略,编译器根据 return 语句自动推导。
  • 当函数体包含多个 return 语句且类型不一致时,必须显式指定返回类型。
    示例
// 自动推导返回类型为 int
auto add = [](int x, int y) { return x + y; };

// 显式指定返回类型为 double
auto divide = [](int x, int y) -> double {
    if (y == 0) return 0.0;
    return static_cast<double>(x) / y;
};

Lambda 的应用场景

作为函数对象(Functor)

std::vector<int> nums = {1, 2, 3, 4};
std::sort(nums.begin(), nums.end(), [](int a, int b) {
    return a > b; // 降序排序
});

异步回调(如 Boost.Asio)

socket.async_read_some(buffer, [this](const error_code& ec, size_t bytes) {
    if (!ec) handle_read(bytes);
});

封装局部逻辑

void process_data(const std::vector<int>& data) {
    int threshold = 10;
    auto filter = [threshold](int x) { return x > threshold; };
    std::copy_if(data.begin(), data.end(), std::back_inserter(result), filter);
}

注意事项

生命周期管理

  • ​按引用捕获:确保被引用的对象在 Lambda 执行时仍然有效,避免悬空引用。
  • ​按值捕获指针:需谨慎,可能造成内存泄漏或悬空指针。

性能

  • 小对象按值捕获更高效,大对象(如容器)建议按引用捕获(需确保生命周期)。

默认捕获的风险

  • 避免使用 [=] 或 [&]:可能导致意外捕获不需要的变量,增加维护难度。

Lambda 与函数对象的关系

  • Lambda 本质上是编译器生成的匿名类(闭包类型)的实例。
  • 捕获的变量会成为该匿名类的成员变量。
  • 等价转换示例
// Lambda 表达式
auto lambda = [x](int y) { return x + y; };

// 编译器生成的等价类
class __AnonymousClosure {
private:
    int x;
public:
    __AnonymousClosure(int x) : x(x) {}
    int operator()(int y) const { return x + y; }
};

总结

特性 关键点
​捕获列表 明确指定需要捕获的变量,避免隐式捕获
​参数列表 与普通函数一致,支持多种传递方式
mutable 允许修改按值捕获的变量副本
​返回类型 可省略(自动推导)或显式指定
​生命周期 谨慎管理按引用捕获的变量,避免悬空引用
​应用场景 函数对象、异步回调、STL 算法等