Lambda 表達式是**匿名函數對象**的語法糖,編譯器會生成一個擁有 `operator()` 的類(閉包類型)。
auto lambda = [capture](params) mutable -> ret { body; };
// 編譯器生成類似:
class __lambda_123 {
// 捕獲變量作為成員
int captured_x;
// 構造函數初始化捕獲
__lambda_123(int x) : captured_x(x) {}
// 函數調用運算符
auto operator()(int y) const { return captured_x + y; }
};
關鍵點:捕獲發生在 Lambda 表達式求值時(即定義語句執行時)
void func() {
int x = 10;
auto f = [x]() { return x; }; // 此處構建閉包對象,捕獲 x 的副本 (值捕獲)
x = 20;
f(); // 返回 10,而非 20
}
| 捕獲方式 | 時機 | 生命周期 | 示例 |
|----------|------|----------|------|
| 值捕獲 `[x]` | 定義處 | 隨閉包對象 | 拷貝構造/移動構造 |
| 引用捕獲 `[&x]` | 定義處 | 綁定原變量 | 必須保證原變量存活 |
| 隱式值捕獲 `[=]` | 定義處 | 隨閉包對象 | 捕獲作用域內所有自動變量 |
| 隱式引用捕獲 `[&]` | 定義處 | 綁定原變量 | 同引用捕獲 |
| 初始化捕獲 `[y=x+1]` (C++14) | 定義處 | 隨閉包對象 | 任意表達式初始化成員 |
auto f = [x]() { return x * 2; };
// ... 可能傳遞給其他線程、存入容器、延遲調用
int result = f(); // 此時執行 operator(),使用捕獲的成員
int x = 42;
auto f = [x]() { return x; };
// 等價於:
struct Closure {
int x; // 成員
Closure(int x_) : x(x_) {} // 構造時拷貝
int operator()() const { return x; }
};
Closure f(x); // 構造時刻捕獲 x 的當前值
int x = 42;
auto f = [&x]() { return x; };
// 等價於:
struct Closure {
int& x; // 成員是引用
Closure(int& x_) : x(x_) {} // 構造時綁定
int operator()() const { return x; }
};
Closure f(x); // 構造時刻綁定 x,後續 x 修改可見
auto ptr = std::make_unique(42);
auto f = [p = std::move(ptr)]() { return *p; };
// 閉包成員為 unique_ptr,構造時移動構造
// 原 ptr 置空,所有權轉移給閉包
std::function createLambda() {
int x = 10;
return [&x]() { return x; }; // 災難:返回引用捕獲的局部變量
}
auto f = createLambda();
f(); // 未定義行為:x 已銷毀
// 1. 值捕獲(默認推薦)
auto f = [x]() { return x; };
// 2. 共享所有權
auto sp = std::make_shared(10);
auto f = [sp]() { return *sp; }; // shared_ptr 拷貝增加引用計數
// 3. 延長生命周期
int x = 10;
auto f = [&x]() { return x; };
// 確保 f 不會在 x 銷毀後調用
int x = 0;
auto f1 = [x]() { x = 10; }; // 錯誤:operator() 默認 const,不可修改捕獲成員
auto f2 = [x]() mutable { x = 10; }; // 正確:去除 const,可修改副本(不影響外部 x)
理解「定義時捕獲,調用時執行」的時空分離,是掌握 Lambda 正確使用的關鍵。