什么是c++闭包?
·
什么是闭包?
闭包是一个能记住并访问其创建时作用域中变量的函数,即使那个作用域已经结束了。
闭包 = 一个函数 + 它创建时所“记住”的外部变量(被捕获的变量)
// 普通函数:空手的旅行者
void traveler() {
// 只能使用路上找到的东西
}
// 闭包:背着背包的旅行者
auto traveler_with_bag = [](/*背包里装的东西*/) {
// 可以随时使用背包里的东西
};
C++ 中闭包的载体:Lambda 表达式
在 C++11 及以后,闭包主要通过 Lambda 表达式实现。
基本语法:
[capture_list](parameter_list) -> return_type {
// function body
}
[capture_list]:捕获列表 —— 决定哪些外部变量被“打包”进闭包(这是闭包的关键!)
(parameter_list):参数列表(和普通函数一样)
-> return_type:返回类型(可省略,编译器自动推导)
{}:函数体
捕获列表
| 捕获方式 | 含义 | 是否构成闭包? |
|---|---|---|
[] | 不捕获任何变量 | ❌ 不是闭包(只是匿名函数) |
[x] | 值捕获 x(拷贝一份) | 是闭包 |
[&x] | 引用捕获 x | 是闭包(但需小心生命周期) |
[=] | 值捕获所有用到的外部变量 | 是闭包 |
[&] | 引用捕获所有用到的外部变量 | 是闭包 |
[this] | 捕获当前对象指针(C++17 起可写 [=, this]) | 是闭包 |
代码示例
1. 值捕获
#include <iostream>
using namespace std;
int main() {
int base = 10;
// 闭包:捕获 base 的值
auto adder = [base](int x) {
return x + base; // 使用被捕获的 base
};
cout << adder(5) << endl; // 输出 15
base = 100; // 修改原变量
cout << adder(5) << endl; // 仍输出 15!因为闭包用的是拷贝
return 0;
}
2. 引用捕获
#include <iostream>
using namespace std;
int main() {
int value = 42;
auto getter = [&value]() { // 引用捕获
return value;
};
value = 100;
cout << getter() << endl; // 输出 100(引用会变)
// 如果 value 被销毁,getter() 就是未定义行为!
return 0;
}
3. 闭包作为函数返回值(经典用法)
#include <iostream>
#include <functional>
using namespace std;
// 返回一个闭包
auto make_multiplier(int factor) {
return [factor](int x) { // 值捕获 factor
return x * factor;
};
}
int main() {
auto double_it = make_multiplier(2);
auto triple_it = make_multiplier(3);
cout << double_it(5) << endl; // 10
cout << triple_it(5) << endl; // 15
// 即使 make_multiplier 已返回,factor 仍有效!
return 0;
}
4.闭包与STL算法的融合
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main() {
vector<int> numbers = {1, 2, 3, 4, 5, 6};
int threshold = 3;
// 用闭包定制查找条件
auto it = find_if(numbers.begin(), numbers.end(),
[threshold](int n) { return n > threshold; }
);
if (it != numbers.end()) {
cout << "First number > " << threshold << " is " << *it << endl;
}
return 0;
}
闭包对象的本质
例如
int a = 5;
auto f = [a](int x) { return x + a; };
等价于
class __lambda_123 {
int a_; // 捕获的变量
public:
__lambda_123(int a) : a_(a) {}
int operator()(int x) const { return x + a_; }
};
__lambda_123 f(a); // f 是一个对象!重载了 operator() 的对象
注意事项
1. 引用捕获的生命周期问题
auto bad() {
int x = 10;
return [&x] { return x; }; // 危险!x 在函数返回后销毁, 正确做法:用值捕获 [x],或确保变量活得足够久。
}
2. 修改被捕获的值
默认 Lambda 是 const 的,不能修改捕获的值:
int count = 0;
auto f = [count]() { count++; }; // 编译错误!
解决方案:加 mutable 关键字
auto f = [count]() mutable { count++; }; // 允许修改拷贝,修改的是拷贝,不影响外部 count。
3. [=]和 [&]的陷阱
int a = 1, b = 2;
auto f = [=, &b]() { // 值捕获所有,但 b 用引用
a = 10; // 错误!a 是值捕获,默认 const
b = 20; // b 是引用,可修改
};
C++ 闭包速查表
| 项目 | 说明 |
|---|---|
| 什么是闭包? | Lambda + 捕获的外部变量 |
| 语法形式 | [capture](params) { body } |
| 关键部分 | 捕获列表 [...] |
值捕获 [x] | 安全,拷贝变量,生命周期由闭包管理 |
引用捕获 [&x] | 高效,但需手动保证变量存活 |
| 本质 | 编译器生成的匿名类对象(重载 operator()) |
| 用途 | 回调、算法定制、延迟计算、状态封装 |
更多推荐



所有评论(0)