Lambda 表达式

一、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\ 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<int>(5)] {

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<int>(0)](int x) mutable {

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; });

相关推荐
-Rane2 小时前
【C++】内存管理
开发语言·c++
水饺编程2 小时前
第4章,[标签 Win32] :绘制信息结构
c语言·c++·windows·visual studio
WBluuue2 小时前
AtCoder Beginner Contest 441(ABCDEF)
c++·算法
晨非辰2 小时前
C++波澜壮阔40年|类和对象篇:拷贝构造与赋值重载的演进与实现
运维·开发语言·c++·人工智能·后端·python·深度学习
hetao17338372 小时前
2026-01-16~19 hetao1733837 的刷题笔记
c++·笔记·算法
玖釉-2 小时前
[Vulkan 学习之路] 29 - 加载模型 (Loading Models)
c++·windows·图形渲染
HelloWorld1024!3 小时前
C++中链表的虚拟头结点:应用场景与使用时机
网络·c++·链表
fakerth3 小时前
【C++】【Linux】从零实现日志库:LogLib 设计与实现详解
c++·日志库
大闲在人3 小时前
Trae builder 实战: 让 C++ 函数像 Python 一样返回多个值
c++·python·ai编程