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

相关推荐
小小龙学IT14 小时前
Go 语言 cgo 与 C/C++ 互操作深度解析:从 fwlib 直连到工业数采网关实战系列
c语言·c++·golang
程序员老陆16 小时前
C++ 多线程通信方式全景:从共享内存到结构化协调
开发语言·c++
某不知名網友17 小时前
ROS2 核心通信:话题发布与订阅详解
开发语言·c++
C++ 老炮儿的技术栈17 小时前
char (*csConnectName)[256]; 和 char csConnectName [256] 有什么区别
java·c语言·开发语言·c++·人工智能·算法·c
大鹏说大话17 小时前
C++ STL 容器怎么选?vector、list、map、unordered_map 对比
开发语言·c++·list
JMchen17 小时前
性能优化——让Native代码飞起来
android·c++·性能优化
chenbingjie_c17 小时前
手撕 C++ priority_queue:二叉堆 + 模板仿函数 + 模板特化(保姆级逐函数拆解)
开发语言·c++
小小龙学IT18 小时前
C++ Redis 客户端深度解析(hiredis 与 redis-plus-plus)——工业数采实时缓存 C++ 侧实战
c++·redis·缓存
垆边人似月.18 小时前
华为机试题 :最长递增子序列题目
数据结构·c++·算法·华为
开发者联盟league18 小时前
c++11 使用chrono库转换时间点和字符串,计算时间点间隔
java·c++·算法