一、为什么需要 lambda 匿名函数?
lambda(λ)是 C++11 引入的匿名函数,核心解决以下问题:
- 临时小函数无需单独定义:对于只使用一次的简单函数(如算法回调、临时逻辑),无需定义独立的函数 / 函数对象,代码更紧凑;
C++11 引入的 Lambda 表达式支持匿名函数定义,解决临时小函数无需单独定义的问题。文章详细讲解了 Lambda 的基本语法结构、捕获子句(值捕获、引用捕获、隐式捕获等)、进阶特性(泛型 Lambda、移动捕获、返回值推导)以及底层实现原理。通过对比普通函数,阐述了 Lambda 在访问外部变量、STL 算法回调及类内成员访问方面的优势,并提供了丰富的代码示例和注意事项。

lambda(λ)是 C++11 引入的匿名函数,核心解决以下问题:
简单来说:lambda 是'即用即丢'的临时函数,尤其适合作为 STL 算法(如 sort、for_each)的参数。
lambda 的完整语法结构如下(部分可省略):
[capture] (parameters) mutable noexcept -> return_type { // 函数体(可执行逻辑) }
| 组成部分 | 作用 | 是否可省略 |
|---|---|---|
[capture] | 捕获子句:指定 lambda 可以访问的外部变量(核心) | ❌ 必须有 |
(parameters) | 参数列表:和普通函数的参数列表一致 | ✅ 可省略 |
mutable | 允许修改值捕获的变量(默认值捕获不可修改) | ✅ 可省略 |
noexcept | 声明 lambda 不抛出异常 | ✅ 可省略 |
-> return_type | 返回值类型:可省略(C++11 起编译器自动推导,C++14 更完善) | ✅ 可省略 |
{ body } | 函数体:执行的逻辑 | ❌ 必须有 |
#include <iostream>
using namespace std;
int main() {
// 最简单的 lambda:无捕获、无参数、无返回值
auto print_hello = []() {
cout << "Hello, lambda!" << endl;
};
// 调用 lambda(和调用普通函数一样)
print_hello(); // 输出:Hello, lambda!
return 0;
}
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <memory>
using namespace std;
// 测试用的类(用于类内 lambda 示例)
class MyClass {
private:
int m_num = 100;
public:
void test_class_lambda();
};
// 用于返回 lambda 的函数(示例 14)
function<int(int)> return_lambda();
int main() {
// ========== 1. 最基础的 lambda:无捕获、无参数、无返回值 ============
// 特点:最简单的 lambda,仅执行固定逻辑,无外部依赖
auto basic_lambda = []() {
cout << "[基础 lambda] 无捕获、无参数、无返回值" << endl;
};
basic_lambda();
// ========== 2. 带参数的 lambda(显式参数类型) =====================
// 特点:和普通函数一样接收参数,无返回值
auto param_lambda = [](int a, int b) {
cout << "[带参数 lambda] a + b = " << a + b << endl;
};
param_lambda(10, 20);
// ========== 3. 显式指定返回值的 lambda =====================
// 特点:C++11 多分支返回值推导失败时必须用,也可提升可读性
auto return_type_lambda = [](int a, int b) -> double {
if (b == 0) return 0.0;
return static_cast<double>(a) / b; // 强制转 double
};
cout << "[显式返回值 lambda] 5/2 = " << return_type_lambda(5, 2) << endl;
// ========== 4. 值捕获外部变量的 lambda =====================
// 特点:拷贝外部变量到 lambda 内部,默认不可修改
int val1 = 10;
auto value_capture_lambda = [val1]() { // val1 = 20; // 错误:值捕获默认不可修改
cout << "[值捕获 lambda] 捕获的 val1 = " << val1 << endl;
};
value_capture_lambda();
// ========== 5. mutable 修饰的值捕获 lambda =====================
// 特点:允许修改值捕获的变量(仅修改内部拷贝,不影响外部)
auto mutable_capture_lambda = [val1]() mutable {
val1 = 20; // mutable 允许修改内部拷贝
cout << "[mutable 值捕获 lambda] 内部修改后的 val1 = " << val1 << endl;
};
mutable_capture_lambda();
cout << "[mutable 值捕获 lambda] 外部 val1 仍为 = " << val1 << endl; // 仍为 10
// ========== 6. 引用捕获外部变量的 lambda =====================
// 特点:引用外部变量,修改会影响外部
int val2 = 30;
auto ref_capture_lambda = [&val2]() {
val2 = 40; // 引用捕获可直接修改外部变量
cout << "[引用捕获 lambda] 修改后的 val2 = " << val2 << endl;
};
ref_capture_lambda();
cout << "[引用捕获 lambda] 外部 val2 同步修改为 = " << val2 << endl; // 变为 40
// ========== 7. 隐式捕获 lambda =====================
// 7.1 隐式值捕获(=):捕获所有外部变量(值拷贝)
int a = 5, b = 6;
auto implicit_val_capture = [=]() {
cout << "[隐式值捕获] a = " << a << ", b = " << b << endl;
};
implicit_val_capture();
// 7.2 隐式引用捕获(&):捕获所有外部变量(引用)
auto implicit_ref_capture = [&]() {
a = 50; b = 60;
cout << "[隐式引用捕获] 修改后 a = " << a << ", b = " << b << endl;
};
implicit_ref_capture();
// ========== 8. 混合捕获 lambda =====================
// 特点:默认捕获 + 指定捕获(优先级更高)
int x = 100, y = 200;
auto mix_capture_lambda = [=, &x]() { // 默认值捕获,仅 x 引用捕获
x = 1000; // 引用捕获可修改
// y = 2000; // 错误:y 是值捕获,不可修改(需加 mutable)
cout << "[混合捕获 lambda] x = " << x << ", y = " << y << endl;
};
mix_capture_lambda();
// ========== 9. 泛型 lambda(C++14+) =====================
// 特点:参数用 auto,支持任意类型参数(类似模板函数)
auto generic_lambda = [](auto val1, auto val2) {
cout << "[泛型 lambda] val1 = " << val1 << ", val2 = " << val2 << endl;
};
generic_lambda(123, 3.14); // int + double
generic_lambda("hello", string("cpp")); // const char* + string
// ========== 10. 立即调用的匿名 lambda =====================
// 特点:定义后立即执行,无需赋值给变量,一次性使用
cout << "[立即调用 lambda] 执行结果:";
[]() {
cout << "匿名 lambda 立即执行" << endl;
}(); // 最后的 () 表示立即调用
// ========== 11. 移动捕获 lambda(C++14+) =====================
// 特点:捕获仅可移动的对象(如 unique_ptr),转移所有权
unique_ptr<int> ptr = make_unique<int>(500);
auto move_capture_lambda = [p = move(ptr)]() {
cout << "[移动捕获 lambda] 捕获的 unique_ptr 值 = " << *p << endl;
};
move_capture_lambda(); // ptr 已为空(所有权转移)
if (!ptr) cout << "[移动捕获 lambda] 外部 ptr 已空" << endl;
// ========== 12. 作为 STL 算法参数的 lambda =====================
// 特点:就地定义回调逻辑,无需单独定义普通函数
vector<int> vec = {5, 2, 9, 1, 5, 6};
sort(vec.begin(), vec.end(), [](int a, int b) {
return a > b; // 降序排序规则
});
cout << "[STL 算法 lambda] 降序排序结果:";
for (int n : vec) cout << n << " ";
cout << endl;
// ========== 13. 类内捕获 this 的 lambda =====================
// 特点:访问类的成员变量/函数,无需传 this 指针
MyClass obj;
obj.test_class_lambda();
// ========== 14. 作为函数返回值的 lambda =====================
// 特点:需用 std::function 包装,可返回带捕获的 lambda
auto returned_lambda = return_lambda();
cout << "[返回 lambda] 调用结果:" << returned_lambda(5) << endl;
return 0;
}
// 类内 lambda 实现(示例 13)
void MyClass::test_class_lambda() {
auto class_lambda = [this]() {
m_num = 200; // 捕获 this,访问类成员变量
cout << "[类内 lambda] 修改后的 m_num = " << m_num << endl;
};
class_lambda();
}
// 返回 lambda 的函数实现(示例 14)
function<int(int)> return_lambda() {
int base = 10; // 返回带值捕获的 lambda,用 std::function 包装
return [base](int x) {
return x + base;
};
}
捕获子句是 lambda 最关键的部分,决定了 lambda 能访问哪些外部变量,以及以何种方式访问(值 / 引用)。
| 捕获语法 | 含义 |
|---|---|
[] | 空捕获:不捕获任何外部变量 |
[var] | 值捕获:拷贝变量 var 到 lambda 内部(lambda 内修改不影响外部) |
[&var] | 引用捕获:引用变量 var(lambda 内修改会影响外部) |
[=] | 隐式值捕获:捕获所有外部变量(值拷贝) |
[&] | 隐式引用捕获:捕获所有外部变量(引用) |
[this] | 类内 lambda 捕获当前对象的 this 指针(可访问类的成员变量 / 函数) |
[=, &var] | 混合捕获:默认值捕获所有变量,仅 var 用引用捕获(C++11 起支持) |
[&, var] | 混合捕获:默认引用捕获所有变量,仅 var 用值捕获 |
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 20;
// 1. 值捕获:拷贝 a、b 到 lambda 内部
auto lambda_val = [a, b]() {
// a = 100; // 错误!值捕获的变量默认不可修改(需加 mutable)
cout << "值捕获:a=" << a << ", b=" << b << endl; // 输出:10,20
};
lambda_val();
// 2. 引用捕获:引用 a、b(修改会影响外部)
auto lambda_ref = [&a, &b]() {
a = 100; b = 200;
cout << "引用捕获修改后:a=" << a << ", b=" << b << endl; // 输出:100,200
};
lambda_ref();
cout << "外部变量:a=" << a << ", b=" << b << endl; // 输出:100,200(外部被修改)
// 3. mutable:允许修改值捕获的变量(仅修改 lambda 内部拷贝,不影响外部)
auto lambda_mutable = [a]() mutable {
a = 999;
cout << "mutable 值捕获:a=" << a << endl; // 输出:999
};
lambda_mutable();
cout << "外部 a:" << a << endl; // 输出:100(外部未变)
return 0;
}
#include <iostream>
using namespace std;
int main() {
int x = 5, y = 6;
// 隐式值捕获:捕获所有外部变量(x、y),值拷贝
auto lambda_implicit_val = [=]() {
cout << "隐式值捕获:x=" << x << ", y=" << y << endl; // 输出:5,6
};
lambda_implicit_val();
// 隐式引用捕获:捕获所有外部变量(x、y),引用
auto lambda_implicit_ref = [&]() {
x = 50; y = 60;
cout << "隐式引用捕获:x=" << x << ", y=" << y << endl; // 输出:50,60
};
lambda_implicit_ref();
// 混合捕获:默认值捕获,仅 x 用引用
auto lambda_mix = [=, &x]() {
x = 500; // 引用捕获,可修改且影响外部
// y = 600; // 错误!y 是值捕获,不可修改(需加 mutable)
cout << "混合捕获:x=" << x << ", y=" << y << endl; // 输出:500,60
};
lambda_mix();
return 0;
}
lambda 在类的成员函数中可以捕获 this 指针,从而访问类的成员变量 / 函数:
#include <iostream>
using namespace std;
class MyClass {
private:
int num = 100;
public:
void func() {
// 捕获 this,访问类成员
auto lambda = [this]() {
num = 200; // 修改成员变量
cout << "类内 lambda:num=" << num << endl; // 输出:200
};
lambda();
}
int get_num() { return num; }
};
int main() {
MyClass obj;
obj.func();
cout << "外部访问:" << obj.get_num() << endl; // 输出:200
return 0;
}
C++11 起,若 lambda 函数体只有 return 语句,编译器可自动推导返回值;C++14 后支持任意函数体的返回值推导:
#include <iostream>
using namespace std;
int main() {
// C++11 支持:单 return 语句自动推导
auto add = [](int a, int b) {
return a + b; // 自动推导返回值为 int
};
cout << add(3, 5) << endl; // 输出:8
// C++14 支持:多分支自动推导(需返回值类型一致)
auto calc = [](int a, int b, char op) {
if (op == '+') return a + b;
else return a - b;
};
cout << calc(10, 3, '-') << endl; // 输出:7
return 0;
}
C++11 对 lambda 返回值自动推导的限制:仅当函数体只有单个 return 语句时能推导,多分支会报错,此时必须用 -> 显式声明返回值类型。
#include <iostream>
using namespace std;
int main() {
// 正确示例:显式指定返回值类型为 double
auto calc = [](int a, int b, char op) -> double {
if (op == '+') return a + b; // int 自动转为 double
else return 0.0; // 原生 double
};
cout << calc(10, 20, '+') << endl; // 输出 30.0(double 类型)
cout << calc(10, 20, '-') << endl; // 输出 0.0(double 类型)
return 0;
}
参数列表中使用 auto,让 lambda 支持任意类型的参数(类似模板函数):
#include <iostream>
#include <string>
using namespace std;
int main() {
// 泛型 lambda:支持任意类型的参数
auto print = [](auto val) {
cout << "泛型 lambda:" << val << endl;
};
print(123); // 输出:123(int)
print(3.14); // 输出:3.14(double)
print("hello"); // 输出:hello(const char*)
print(string("cpp")); // 输出:cpp(string)
return 0;
}
lambda 可作为 STL 算法的参数(最常用场景),也可作为函数返回值(需用 std::function):
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> // std::function 头文件
using namespace std;
// lambda 作为函数参数(用 std::function 接收)
void process_data(int a, int b, function<int(int, int)> func) {
cout << "处理结果:" << func(a, b) << endl;
}
// lambda 作为返回值
function<int(int)> get_lambda() {
int base = 10; // 返回一个 lambda(捕获 base)
return [base](int x) {
return x + base;
};
}
int main() {
// 1. lambda 作为 STL 算法参数(排序)
vector<int> vec = {5, 2, 9, 1, 5, 6};
// 自定义排序规则:降序
sort(vec.begin(), vec.end(), [](int a, int b) {
return a > b;
});
cout << "降序排序:";
for (int n : vec) cout << n << " "; // 输出:9 6 5 5 2 1
cout << endl;
// 2. lambda 作为函数参数
process_data(10, 20, [](int a, int b) {
return a * b;
}); // 输出:200
// 3. lambda 作为返回值
auto func = get_lambda();
cout << "返回 lambda 调用:" << func(5) << endl; // 输出:15(5+10)
return 0;
}
可以用 std::move 捕获仅可移动的变量(如 std::unique_ptr):
#include <iostream>
#include <memory>
using namespace std;
int main() {
unique_ptr<int> ptr = make_unique<int>(100);
// 移动捕获:将 ptr 的所有权转移到 lambda 内部
auto lambda = [p = move(ptr)]() {
cout << "移动捕获:" << *p << endl; // 输出:100
};
lambda(); // ptr 已为空(所有权转移)
if (!ptr) cout << "外部 ptr 已空" << endl;
return 0;
}
lambda 并非'魔法',编译器会将 lambda 转换为匿名的函数对象(仿函数):
operator() 重载;mutable 对应 operator() 重载为非 const(值捕获的成员变量默认是 const,需 mutable 解除)。比如以下 lambda:
int a = 10;
auto lambda = [a]() mutable { a++; };
编译器会生成类似这样的代码:
// 编译器生成的匿名类(伪代码)
class __lambda_12345 { // 12345 是编译器生成的唯一标识
private:
int a; // 值捕获的变量
public:
__lambda_12345(int a_) : a(a_) {}
void operator()() { // mutable 对应非 const
a++;
}
};
// 实际调用
__lambda_12345 lambda(10);
lambda();
this 捕获的风险:若 lambda 的生命周期超过对象生命周期,this 会悬空;引用捕获的生命周期:若 lambda 的生命周期超过被引用变量的生命周期,会导致悬空引用(访问已释放的内存);
// 错误示例:返回引用捕获局部变量的 lambda
auto bad_lambda() {
int x = 10;
return [&x]() { cout << x << endl; }; // x 已销毁,调用时未定义行为
}
| 对比维度 | 普通函数 | lambda 匿名函数 |
|---|---|---|
| 定义位置 | 只能定义在全局 / 命名空间 / 类内(不能在函数内定义普通函数) | 可定义在任意代码块内(函数内、循环内、if 内) |
| 访问外部变量 | 只能通过「传参」或「全局变量」(无其他方式) | 可通过「捕获子句」灵活访问当前作用域的变量(值 / 引用) |
| 复用性 | 天生支持复用(定义一次,多处调用) | 默认匿名,仅当前作用域可用(如需复用需赋值给变量) |
| 命名要求 | 必须有唯一名称(易造成命名污染) | 无需命名(一次性使用),也可赋值给变量命名 |
| 类型特性 | 固定的函数类型,无法直接作为参数传递(需函数指针 / 包装) | 编译器生成匿名函数对象,可直接作为参数(如 STL 算法回调) |
| 类内场景 | 需传 this 指针才能访问类成员 | 可直接捕获 this,便捷访问类成员变量 / 函数 |
| 回调便捷性 | 作为回调需借助函数指针 / std::function 包装,步骤繁琐;若回调需访问外部状态,需额外封装(全局变量 / 类对象),代码冗余 | 可直接作为回调参数传递(无需包装);若需访问外部状态,通过捕获子句即可实现,无需额外封装,代码简洁 |
普通函数要访问当前作用域的变量,只有两种方式:传参(麻烦)或全局变量(危险,易污染);而 lambda 可以通过「捕获子句」直接访问,无需额外操作。
#include <iostream>
using namespace std;
// 普通函数:要访问外部的 factor,必须传参
int multiply(int num, int factor) {
return num * factor;
}
int main() {
int factor = 5; // 局部变量
// 调用普通函数:必须手动传 factor
cout << multiply(10, factor) << endl; // 输出 50
cout << multiply(20, factor) << endl; // 输出 100
return 0;
}
#include <iostream>
using namespace std;
int main() {
int factor = 5; // 局部变量
// lambda:直接捕获 factor,无需传参
auto multiply = [factor](int num) {
return num * factor;
};
// 调用时只需传 num,factor 已被捕获
cout << multiply(10) << endl; // 输出 50
cout << multiply(20) << endl; // 输出 100
return 0;
}
普通函数作为 STL 算法的回调时,需要单独定义(代码跳来跳去);lambda 可以「就地定义」,逻辑和调用位置在一起,可读性大幅提升。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 普通函数:排序规则(降序),需单独定义
bool compare(int a, int b) {
return a > b;
}
int main() {
vector<int> vec = {5, 2, 9, 1, 5, 6};
// 调用 sort,传入普通函数名
sort(vec.begin(), vec.end(), compare);
for (int n : vec) cout << n << " "; // 9 6 5 5 2 1
return 0;
}
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> vec = {5, 2, 9, 1, 5, 6};
// lambda:排序规则直接写在 sort 参数里,无需跳转到其他位置
sort(vec.begin(), vec.end(), [](int a, int b) {
return a > b; // 降序规则
});
for (int n : vec) cout << n << " "; // 9 6 5 5 2 1
return 0;
}
对于只使用一次的小逻辑,普通函数需要起名字(哪怕只用一次),容易造成'命名污染';lambda 匿名使用,用完即丢,无需命名。
#include <iostream>
using namespace std;
// 只用一次的小函数,却要起名字(比如叫 print_welcome)
void print_welcome() {
cout << "欢迎使用本程序!" << endl;
}
int main() {
// 仅调用一次
print_welcome(); // 后续再也不用这个函数,但它的名字仍占用命名空间
return 0;
}
#include <iostream>
using namespace std;
int main() {
// 匿名 lambda:直接定义 + 调用,无需命名,用完即销毁
[]() {
cout << "欢迎使用本程序!" << endl;
}(); // 最后的 () 表示立即调用
return 0;
}
普通函数要访问类的成员变量,需要传 this 指针或对象;lambda 可以直接捕获 this,一键访问类成员。
#include <iostream>
using namespace std;
class MyClass {
private:
int base = 100;
public:
// 普通函数:需传 this 指针才能访问 base
static int add(MyClass* obj, int num) {
return obj->base + num;
}
void func() {
// 调用普通函数,必须传 this
cout << add(this, 50) << endl; // 输出 150
}
};
int main() {
MyClass obj;
obj.func();
return 0;
}
#include <iostream>
using namespace std;
class MyClass {
private:
int base = 100;
public:
void func() {
// lambda:捕获 this,直接访问 base
auto add = [this](int num) {
return this->base + num; // 也可省略 this->,直接 base
};
cout << add(50) << endl; // 输出 150
}
};
int main() {
MyClass obj;
obj.func();
return 0;
}

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online