浅显易懂的 Lambda 表达式介绍
文章目录
1. Lambda 表达式的作用
Lambda 表达式可以理解为一个 “临时的小函数”,允许你在需要函数的地方 快速定义一个匿名函数。它的核心作用:
- 简化代码:无需单独定义函数,直接在调用处写逻辑。
- 捕获上下文变量:可以自动捕获外部变量(类似“记住”外部的值)。
- 灵活传递:可作为参数传递给其他函数(如 STL 算法中的排序、遍历等)。
2. 基本语法
Lambda 的典型结构(按需组合):
[捕获列表] (参数列表) -> 返回类型 {
// 函数体
}
示例 1:最简单的 Lambda
auto sayHello = []() {
std::cout << "Hello, Lambda!";
};
sayHello(); // 调用 Lambda
示例 2:带参数和返回值的 Lambda
auto add = [](int a, int b) -> int {
return a + b;
};
int result = add(3, 5); // result = 8
示例 3:捕获外部变量
int x = 10;
auto printX = [x]() { // 值捕获(复制 x 的值)
std::cout << x; // 输出 10
};
printX();
3. 捕获列表的规则
[]
:不捕获任何变量。[x]
:值捕获变量x
(复制一份)。[&x]
:引用捕获变量x
(直接操作原变量)。[=]
:值捕获所有外部变量。[&]
:引用捕获所有外部变量。[this]
:捕获当前类的this
指针。
示例:修改外部变量(需引用捕获)
int count = 0;
auto increment = [&count]() {
count++; // 引用捕获,修改原变量
};
increment();
std::cout << count; // 输出 1
4. 底层实现原理
Lambda 表达式在 C++ 中并不是魔法,编译器会将它转换为一个 匿名类的对象:
- 生成匿名类:编译器为每个 Lambda 生成一个唯一的类。
- 重载
operator()
:函数体变为该类的operator()
方法。 - 捕获变量变为成员变量:根据捕获方式(值/引用),生成对应的成员。
示例:Lambda 的等价类
// 假设有一个 Lambda:
int y = 5;
auto lambda = [y](int a) { return y + a; };
// 编译器生成的类似代码:
class __AnonymousClass {
private:
int y; // 值捕获的变量
public:
__AnonymousClass(int y) : y(y) {}
int operator()(int a) const {
return y + a;
}
};
__AnonymousClass lambda(y);
5. 常见用途
(1) STL 算法中的回调
#include <vector>
#include <algorithm>
std::vector<int> nums = {3, 1, 4, 1, 5};
// 使用 Lambda 排序(从小到大)
std::sort(nums.begin(), nums.end(), [](int a, int b) {
return a < b;
});
(2) 简化线程任务
#include <thread>
std::thread t([]() {
std::cout << "Running in a thread!";
});
t.join();
(3) 延迟执行逻辑
auto task = [](int delay) {
std::this_thread::sleep_for(std::chrono::seconds(delay));
std::cout << "Done!";
};
task(2); // 2 秒后输出
6. 注意事项
- 避免悬垂引用:若 Lambda 的引用捕获变量已销毁,会导致未定义行为。
mutable
关键字:若需在值捕获后修改副本,需声明mutable
:int a = 0; auto modify = [a]() mutable { a++; // 修改的是副本 };
总结
- Lambda 是什么:一个可捕获外部变量的匿名函数对象。
- 何时用:简化一次性函数逻辑,尤其是需要捕获上下文时。
- 底层实现:编译器生成匿名类,捕获变量作为成员,函数体作为
operator()
。
通过 Lambda,你可以像写普通代码一样写函数逻辑,同时灵活地“记住”外部变量!