这个问题可以从以下几个层面来回答,既能体现基础扎实,也能带出一些进阶理解。


1. 基本概念

Lambda表达式是C++11引入的一种匿名函数对象,可以就地定义,主要用来写短小的回调、谓词或局部功能,避免额外写一个函数或函数对象。它的本质是编译器帮我们生成一个匿名类的重载operator()

2. 语法结构

标准形式:

[捕获列表](参数列表) mutable(可选) -> 返回类型 { 函数体 }
  • 捕获列表:决定怎么访问外部变量。

  • 参数列表:和普通函数一样,参数可有可无。

  • mutable:如果加了,允许修改按值捕获的副本(否则默认是const的)。

  • 返回类型:一般可省略,由编译器推导。

  • 函数体:具体实现。

最简单的例子:

auto add = [](int a, int b) { return a + b; };

3. 捕获方式(重点)

  • [=]:值捕获所有外部变量(拷贝一份,只读,除非加mutable)。

  • [&]:引用捕获所有外部变量(可以修改,但要保证lambda执行时变量还活着)。

  • [this]:捕获当前类的this指针,可访问成员变量和函数。

  • 混合捕获[a, &b] 以值捕获a,引用捕获b;[=, &x] 大部分值捕获,x引用捕获;[&, x] 大部分引用捕获,x值捕获。

  • C++14后支持初始化捕获[x = std::move(obj)] 可以把外部变量移动进来,或者[y = 10]直接初始化一个变量在lambda内部。

4. 参数和返回类型

  • 参数列表可以像普通函数一样有默认值(C++14起)。

  • 返回类型通常可推导,但如果函数体里有多个return且类型不统一,就要显式指定 -> type

  • C++14泛型lambda:参数类型可用auto,即:

    auto f = [](auto a, auto b) { return a + b; };

    这相当于模板化的operator()

5. 常用场景

  • STL算法sortfind_iffor_each 等。

    std::sort(vec.begin(), vec.end(), [](int a, int b){ return a > b; });
  • 异步/回调:作为线程函数或事件处理函数。

  • 局部封装:避免在类里加一堆细碎的辅助函数。

  • 立即执行:定义并马上调用,比如[&]{ /* 初始化代码 */ }();

6. 和函数指针、std::function的区别

  • 无捕获的lambda可以隐式转换成函数指针。

  • 有捕获的lambda只能用std::function或模板(auto)来保存,因为它带有状态。

  • std::function 是一个通用多态函数包装器,可以装下任何可调用对象(函数指针、lambda、bind、函数对象),但会有一点性能开销(类型擦除),在性能敏感的地方最好直接用auto或模板接收lambda。

7. 本质与注意事项

  • 每个lambda类型都是唯一的、匿名编译器生成的类型,所以即使用相同的定义,两个lambda的类型也不同,除非用std::function或模板。

  • 值捕获的变量默认在lambda内不能修改,加mutable后可修改,但改的是副本。

  • 避免引用捕获局部变量后,lambda的生命周期长于变量,造成悬空引用。

  • C++17起,lambda在常量表达式中(constexpr)使用也可以隐式转为函数指针。


总之,lambda就是“短小、就地、带状态”的函数对象,现代C++中非常核心,能大幅提升代码的可读性和局部逻辑的封装性。

(如果面试官愿意深入,还可以接着聊到底层的闭包生成、捕获列表的存储布局等)

2026版C++八股文

更多推荐