✅ 一、Lambda 是什么
一句话:
Lambda 表达式 = 轻量函数(匿名函数)
不需要声明名字、不需要单独写函数体,直接在代码里用。
✳ 二、C++ Lambda 基本格式
C++ 最完整语法:
capture(parameter_list) mutable noexcept -> return_type { body }
最常见精简格式:
\&(int x){ return x + 1; }
✳ 三、参数说明
| 部分 | 含义 |
|---|---|
[capture] |
捕获外部变量 |
(parameter_list) |
参数列表 |
mutable |
允许修改捕获变量 |
return_type |
返回类型 |
{ body } |
实现代码 |
⚡ 四、捕获(capture)的写法重点
捕获方式决定 Lambda 能否访问外部变量
例1:按值捕获
int a = 10;
auto f = a() { return a + 1; };
例2:按引用捕获
int a = 10;
auto f = \&a() { a++; };
f();
执行后 a == 11
例3:全部按值捕获
=() { ... }
例4:全部按引用捕获
\&() { ... }
例5:混合捕获
=,\&x(){ ... }
🧰 五、典型使用场景
① 线程回调 / 异步执行
std::thread t(\[\]{
printf("worker\n");
});
t.join();
② STL 回调(最常用)
std::vector<int> v{1,2,3,4};
std::for_each(v.begin(), v.end(), \[\](int x){
std::cout << x << " ";
});
③ 排序自定义
std::sort(v.begin(), v.end(),
\[\](int a, int b){ return a > b; });
🔧 六、底层实现
C++ Lambda 本质是:
编译器生成一个匿名类(仿函数 functor)
int a = 10;
auto f = a() { return a+1; };
等价于:
struct _Lambda {
int a;
int operator()() const {
return a+1;
}
};
所以:
-
捕获变量 → 编译器生成成员变量
-
调用 → 通过
operator()执行
这一点和 std::function / function pointer 不一样。
🚩 七、常见坑
❗ 1. 捕获值不会更新原变量
int a = 10;
auto f = a(){ return a++; };
f();
printf("%d\n", a); // 输出 10(不会变)
需要引用:
auto f = \&a(){ a++; };
❗ 2. 捕获 this
类内使用很常见:
auto f = this() { this->run(); };
🚀 八、和函数指针对比
| 函数指针 | Lambda | |
|---|---|---|
| 是否捕获外部变量 | ❌ 不行 | ✔ 可以 |
| 创建方式 | 需要函数名 | 无名即可 |
| 内联优化 | 一般 | 强 |
| 易用性 | 差 | 好 |
高级用法:
1️⃣ 泛型 Lambda (C++14+)
允许参数类型自动推断:
auto add = \[\](auto a, auto b){ return a + b; };
add(1, 2); // int
add(1.5, 2.2); // double
add("a"s, "b"s); // string
2️⃣ 可变参数 Lambda (C++20)
auto print = \[\](auto... args){
(std::cout << ... << args) << "\n";
};
print(1, "hello", 3.14);
3️⃣ mutable 捕获值可修改
默认按值捕获是 const 的:
int x = 10;
auto f = x() mutable {
x++;
return x;
};
f(); // 11
4️⃣ 捕获 this 指针
类内非常常见:
auto f = this { doWork(); };
如果你写:
=
类内也隐式捕获 this
但 C++20 允许捕获 this 的副本(防悬垂):
auto f = \*this { doWork(); };
等于复制整个对象避免悬空指针。
5️⃣ 初始化捕获(C++14+重要能力)
auto f = val = std::move(bigObj) {
use(val);
};
变量 val 只存在 Lambda 内
特别适合智能指针:
auto f = p = std::make_shared\
std::cout << *p;
};
甚至可以这样:
auto f = i=0() mutable {
return ++i;
};
f(); //1
f(); //2
这种行为 = 闭包(closure)状态保持
6️⃣ constexpr Lambda(C++17+)
constexpr auto sqr = \[\](int x) { return x*x; };
static_assert(sqr(5) == 25);
还能在编译期算 Fibonacci:
constexpr auto fib = \[\](int n){
if (n <= 1) return n;
return fib(n-1) + fib(n-2);
};
7️⃣ 返回类型显式指定
当需要强制返回类型:
auto f = \[\](int x) -> double {
if(x > 0) return x;
return 0.5;
};
8️⃣ Lambda + std::function
⚠ 注意性能区别:
std::function<int(int)> f = [](int x){ return x + 1; };
会发生:
-
类型擦除
-
动态分配(可能)
-
低效
推荐保留 auto
auto f = [](int x){ return x+1; };
9️⃣ Lambda 做状态机(闭包)
比如计数器:
auto counter = i = 0() mutable {
return ++i;
};
counter(); //1
counter(); //2
counter(); //3
多线程共享状态:
auto sum = total = std::atomic\
total += x;
};
这就是函数式闭包的力量。
🔟 Lambda 捕获移动对象
最重要的例子:线程池任务提交
pool.push(task=std::move(task)() mutable {
task();
});
⭐ 高级技巧加一条:模板 Lambda(C++20)
auto add = \[\]<typename T>(T a, T b){
return a + b;
};
⚙ 底层实现补充
Lambda 本质上:
编译器生成
struct+operator()
带捕获:
int x = 10;
auto f = [x]{ return x+1; };
等价于
struct _lambda {
int x;
int operator()() const { return x+1; }
};
🚩 性能注意点
| 写法 | 性能 |
|---|---|
| auto lambda | 🟢 最快 |
| template lambda | 🟢 最快 |
| std::function | 🔴 可能动态分配,慢 |
| bind | 🔴 更慢/不推荐 |
🧨 STL 中的高阶组合
std::sort(v.begin(), v.end(),
\[\](auto &a, auto &b){
return a.score > b.score;
}
);
过滤:
auto it = std::remove_if(v.begin(), v.end(),
\&(auto &n){ return n < 0; });