🎁個人主頁:工藤新一1
🔍系列專欄:C++面向對象(類和對象篇)
🌟心中的天空之城,終會照亮我前方的路
🎉歡迎大家點贊👍評論📝收藏?文章
文章目錄
- Lambda
- 一、Lambda表達式語法
- 二、Lambda 表達式的應用
- 三、捕捉列表
- 3.1概念與功能描述
- 3.2mutable
- 四、Lambda 的原理
- 五、Lambda 捕獲懸垂引用問題
Lambda
一、Lambda表達式語法
? lambda
表達式本質是一個匿名函數對象,跟普通函數不同的是他可以定義在函數內部。lambda
表達式語法使用層而言沒有類型,所以我們?般是? auto
或者模板參數定義的對象去接收 lambda
對象
lambda
表達式特點:輕量級- 快速定義一個匿名函數對象(也被稱作:CLosure 閉包)
lambda
表達式的格式:[capatrue-list](parameters)-> return type { function body }
-
[capatrue-list]:
捕捉列表,該列表總是出現在[lambda]
函數的開始位置,編譯器根據[]
來判斷接下來的代碼是否為lambda
函數,捕捉列表能夠捕捉上下文中的變量 供lambda
函數使用,捕捉列表可以傳值和傳引用捕捉(注意:即使捕捉列表為空也不能被省略)
-
(parameters):
參數列表,與普通函數的參數列表功能類似,如果不需要參數傳遞,那么即可連同()
一起省略 -
-> return type:
返回值類型,用追蹤返回類型形式聲明函數的返回值類型,沒有返回值時此部分可省略。一般返回值類型明確的情況下,也可省略,由編譯器對返回類型進行推導 -
{ function body }:
函數體,函數體內的實現跟普通函數完全類似,在該函數體內,除了使用其參數外,還可使用所有捕獲到的變量,函數體為空時也不能被省略。
二、Lambda 表達式的應用
? 在學習 lambda
表達式之前,我們的使?的可調?對象只有 函數指針 和 仿函數對象,函數指針的類型定義起來?較?煩,仿函數要定義?個類,相對會?較?煩。使用 lambda
去定義可調?對象,既簡單又方便
? lambda
在很多其他地??起來也很好?,?如 線程 中定義線程的執?函數邏輯,智能指針 中定制 刪除器 等,lambda
的應?還是很?泛的,以后我們會不斷接觸到
三、捕捉列表
3.1概念與功能描述
? lambda
表達式中默認只能用 lambda
函數體和參數中的變量,如果想運?外層作?域中的變量則需要進行 “捕捉”
- 第一種捕捉方式:在捕獲列表中顯示 傳值捕獲(變量只讀狀態),傳引用捕獲,捕獲多個變量用逗號進行分割。
[ x, y, &z ]
表示x
和y
值捕獲,z
引用捕獲 - 第?種捕捉方式:在捕捉列表中隱式捕捉,在捕捉列表寫?個
=
表?隱式值捕捉(將變量全部變為值捕捉),在捕捉列表 寫?個&
表?隱式引用捕捉,這樣我們lambda
表達式中使用的那些變量,編譯器就會對其進行?動捕捉
注意:隱式捕獲,不是將程序中的所有變量都捕捉到 **lambda** 表達式中,而是需要哪個,捕獲哪個
- 第三種捕捉方式:在捕捉列表中混合使?隱式捕捉和顯?捕捉,
[ = , &x ]
表?其他變量隱式值捕捉,x
引?捕捉;[ &, x, y ]
表?其他變量引?捕捉,x
和y
值捕捉。當使?混合捕捉時,第?個元素必須是& 或 =
,并且&
混合捕捉時,后?的捕捉變量必須是值捕捉,同理=
混合捕捉時,后?的捕捉變量必須是引?捕捉。
lambda
表達式在函數局部域中,他可以捕捉lambda
位置之前定義的變量,不能捕捉靜態局部變量和全局變量,靜態局部變量和全局變量也不需要捕捉,lambda
表達式中可以直接使用。這也意味著**lambda
** 表達式如果定義在全局位置,捕獲列表必須為空
3.2mutable
- 默認情況下,
lambda
捕捉列表是被const
修飾的,也就是說傳值捕捉而來的對象不能被修改,mutable
加在參數列表的后?可以 取消其常量性,也就說使?該修飾符后,傳值捕捉的對象就可以被修改了,但是修改還是形參對象,不會影響實參(類似值傳遞,返回的是自身數據的一份臨時拷貝)— — 被 lambda 通過 “傳值捕獲” 的內部變量,本質是外部變量的一份臨時拷貝。使用mutable
修飾符后,參數列表不可省略(即使參數不能為空)。
四、Lambda 的原理
? lambda
的原理和 范圍for 很像,編譯后從匯編指令層的?度看,壓根就沒有 lambda
和 范圍for 這樣的東西。范圍for 底層是迭代器,?lambda
底層是仿函數對象,也就說我們寫了?個 lambda
以后,編譯器會?成?個對應的仿函數的類
? 仿函數的類名是編譯按?定規則?成的,保證不同的 lambda
?成的類名不同,lambda
參數/返 回類型/函數體就是仿函數 operator()
的參數/返回類型/函數體, lambda
的捕獲列表本質是?成 的仿函數類的成員變量,也就是說捕獲列表的變量都是 lambda
類構造函數的實參,當然隱式捕獲,編譯器要看使?哪些就傳那些對象
- 上?的原理,我們可以透過 匯編層 了解?下
class Rate
{
public:Rate(double rate): rate(rate) {}double operator()(double money, int year){return money * rate * year;}private:double rate;
};int main()
{double rate = 0.49;//仿函數對象Rate r1(rate);r1(1000, 2);auto func1 = [](){cout << "Hello World" << endl;}; func1();//lambda//捕獲列表中的rate,可以視作 lambda 類構造函數的參數傳遞auto r2 = [rate](double money, int year){return money * rate * year;};r2(1000, 2);return 0;
}
- 本質上都是給構造函數傳參
-
定義
lambda
- 生成仿函數 -
定義
lambda
對象 - 初始化仿函數對象
五、Lambda 捕獲懸垂引用問題
此外,多線程中如果 捕獲引用,也可能出現 引用失效 的問題,這會導致程序結果錯誤或訪問異常等;而對于 傳值捕獲 則不會出現這種問題
🌟 各位看官好,我是工藤新一1呀~
🌈 愿各位心中所想,終有所致!