杭州富陽(yáng)做網(wǎng)站百度云網(wǎng)盤(pán)資源搜索
目錄
1.引言
2.Lambda 的本質(zhì)
3.Lambda 的捕獲機(jī)制的本質(zhì)
4.捕獲方式的實(shí)現(xiàn)與底層原理
5.默認(rèn)捕獲的實(shí)現(xiàn)原理
6.捕獲 this 的機(jī)制
7.捕獲的限制與注意事項(xiàng)
8.總結(jié)
1.引言
????????C++ 中的 Lambda 表達(dá)式是一種匿名函數(shù),最早在 C++11 引入,用于簡(jiǎn)化函數(shù)對(duì)象的定義和使用。它以更簡(jiǎn)潔的語(yǔ)法提供了強(qiáng)大的功能,但其本質(zhì)和捕獲機(jī)制背后有許多值得深究的細(xì)節(jié)。本文將探討 Lambda 的本質(zhì),以及捕獲的底層實(shí)現(xiàn)與原理。
2.Lambda 的本質(zhì)
????????Lambda 是一個(gè)語(yǔ)法糖,本質(zhì)上是由編譯器生成的一個(gè)匿名類,該類重載了?operator()
(即調(diào)用運(yùn)算符)。在使用 Lambda 表達(dá)式時(shí),編譯器會(huì)隱式生成一個(gè)這樣的類,并在必要時(shí)捕獲上下文中的變量。
????????示例與編譯器生成的代碼對(duì)比
#include <iostream>
#include <functional>int main() {int x = 10;auto lambda = [x](int y) { return x + y; };std::cout << lambda(20) << std::endl; // 輸出 30return 0;
}
編譯器會(huì)將上述 Lambda 轉(zhuǎn)換為類似以下的代碼:
#include <iostream>
#include <functional>class LambdaClass {int x;
public:LambdaClass(int x) : x(x) {}int operator()(int y) const {return x + y;}
};int main() {int x = 10;LambdaClass lambda(x);std::cout << lambda(20) << std::endl; // 輸出 30return0;
}
可以看到,Lambda 實(shí)際上是一個(gè)具有捕獲變量?x
?的函數(shù)對(duì)象。
3.Lambda 的捕獲機(jī)制的本質(zhì)
Lambda 的捕獲機(jī)制允許其在定義時(shí)綁定外部作用域中的變量,以便在 Lambda 內(nèi)部使用。這一機(jī)制本質(zhì)上是通過(guò)捕獲變量并存儲(chǔ)為匿名類的成員變量來(lái)實(shí)現(xiàn)的。
捕獲的兩種方式
1)值捕獲(capture by value):?捕獲外部變量的副本,保存在 Lambda 的內(nèi)部。
2)引用捕獲(capture by reference):?捕獲外部變量的引用,Lambda 內(nèi)部直接訪問(wèn)外部變量。
4.捕獲方式的實(shí)現(xiàn)與底層原理
1)值捕獲的實(shí)現(xiàn)?值捕獲會(huì)在 Lambda 表達(dá)式創(chuàng)建時(shí),將捕獲的變量拷貝到匿名類的成員變量中。每次調(diào)用 Lambda 時(shí),使用的是捕獲時(shí)的副本。
#include <iostream>int main() {int x = 10;auto lambda = [x]() { std::cout << x << std::endl; };x = 20;lambda(); // 輸出 10,而非 20return 0;
}
編譯器生成的代碼類似于:
class Lambda {int x; // 保存捕獲的副本
public:Lambda(int x) : x(x) {}void operator()() const {std::cout << x << std::endl;}
};
這里,x
?是一個(gè)副本,與原始變量脫離關(guān)系。
2)引用捕獲的實(shí)現(xiàn)?引用捕獲則是將外部變量的引用存儲(chǔ)為 Lambda 類的成員變量,調(diào)用時(shí)直接操作原變量。
#include <iostream>int main() {int x = 10;auto lambda = [&x]() { std::cout << x << std::endl; };x = 20;lambda(); // 輸出 20return 0;
}
編譯器生成的代碼類似于:
class Lambda {int& x; // 保存外部變量的引用
public:Lambda(int& x) : x(x) {}void operator()() const {std::cout << x << std::endl;}
};
可以看到,引用捕獲直接存儲(chǔ)的是外部變量的引用,Lambda 的調(diào)用會(huì)影響原變量。
5.默認(rèn)捕獲的實(shí)現(xiàn)原理
1)默認(rèn)值捕獲?[=]
:?使用?[=]
?會(huì)默認(rèn)按值捕獲外部作用域的所有變量。
int x = 10, y = 20;
auto lambda = [=]() { return x + y; }; // 默認(rèn)值捕獲 x 和 y
等價(jià)于:
class Lambda {int x, y;
public:Lambda(int x, int y) : x(x), y(y) {}int operator()() const {return x + y;}
};
2)默認(rèn)引用捕獲?[&]
:?使用?[&]
?會(huì)默認(rèn)按引用捕獲外部作用域的所有變量。
int x = 10, y = 20;
auto lambda = [&]() { return x + y; }; // 默認(rèn)引用捕獲 x 和 y
等價(jià)于:
class Lambda {int& x, & y;
public:Lambda(int& x, int& y) : x(x), y(y) {}int operator()() const {return x + y;}
};
6.捕獲 this 的機(jī)制
????????捕獲?this
?時(shí),實(shí)際上是按值捕獲了?this
?指針,使得 Lambda 可以訪問(wèn)當(dāng)前對(duì)象的成員變量。如果捕獲?*this
,則表示按值捕獲整個(gè)對(duì)象。
????????示例:捕獲 this
#include <iostream>class MyClass {int data = 42;
public:auto createLambda() {return [this]() { std::cout << data << std::endl; };}
};int main() {MyClass obj;auto lambda = obj.createLambda();lambda(); // 輸出 42return0;
}
編譯器生成的代碼類似于:
class Lambda {MyClass* obj; // 捕獲 this 指針
public:Lambda(MyClass* obj) : obj(obj) {}void operator()() const {std::cout << obj->data << std::endl;}
};
7.捕獲的限制與注意事項(xiàng)
1)不能捕獲動(dòng)態(tài)生成的變量:?Lambda 只能捕獲作用域中已有的變量,不能捕獲運(yùn)行時(shí)動(dòng)態(tài)生成的變量。
2)捕獲的生命周期:?引用捕獲的變量必須保證 Lambda 的生命周期不超過(guò)捕獲對(duì)象。
3)與 mutable 相關(guān)的限制:?捕獲的變量默認(rèn)是不可變的(即?const
)。如果需要修改捕獲的變量,需要顯式添加?mutable
。
8.總結(jié)
1)Lambda 的本質(zhì):?是一個(gè)匿名類,其捕獲的變量存儲(chǔ)為類的成員變量,調(diào)用時(shí)通過(guò)重載的?operator()
?實(shí)現(xiàn)。
2)捕獲的本質(zhì):?值捕獲是將外部變量的副本存儲(chǔ)為類成員,引用捕獲是將外部變量的引用存儲(chǔ)為類成員。
3)注意事項(xiàng):?使用 Lambda 時(shí),需要特別關(guān)注變量的生命周期和捕獲方式,以避免未定義行為。
Lambda 表達(dá)式在 C++ 中提供了極大的靈活性和簡(jiǎn)潔性,特別是在需要定義短小的回調(diào)函數(shù)或處理算法時(shí)。理解并熟練使用 Lambda 表達(dá)式可以顯著提升代碼的可讀性和效率。