面试官提问:lambda表达式了解多少?简单说说用法?
这个问题可以从以下几个层面来回答,既能体现基础扎实,也能带出一些进阶理解。
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算法:
sort,find_if,for_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++中非常核心,能大幅提升代码的可读性和局部逻辑的封装性。
(如果面试官愿意深入,还可以接着聊到底层的闭包生成、捕获列表的存储布局等)
更多推荐
所有评论(0)