C++11新特性中的匿名函數Lambda表達式的彙編實現分析(一)閉包
首先,讓咱們來看看以&方式進行變量捕獲,一樣沒有參數和返回。
函數
int main() { int a = 0xB; auto lambda = [&]{ a = 0xA; }; lambda(); return 0; }
閉包中將main中a變量改寫爲0xA。this
main中的關鍵彙編代碼:spa
int a = 0xB; mov dword ptr [ebp-8],0Bh auto lambda = [&]{ a = 0xA; }; lea eax,[ebp-8] push eax lea ecx,[ebp-14h] call 002D1BE0 lambda(); lea ecx,[ebp-14h] call 002D1C20 return 0;
一樣的,進入閉包前要調用一個拷貝函數。.net
002D1BE0 內:code
pop ecx mov dword ptr [ebp-8],ecx mov eax,dword ptr [ebp-8] mov ecx,dword ptr [ebp+8] mov dword ptr [eax],ecx mov eax,dword ptr [ebp-8] pop edi pop esi pop ebx mov esp,ebp pop ebp ret 4
和前面一篇文章中的代碼基本一致,可是有兩個地方不一樣,對象
上文寫到:blog
pop ecx 內存
mov dword ptr [ebp-8],ecx get
mov eax,dword ptr [ebp-8]
mov ecx,dword ptr [ebp+8]
mov edx,dword ptr [ecx]
mov dword ptr [eax],edx
mov eax,dword ptr [ebp-8]
注意黑體部分,若採用[=]的捕獲方式,那麼將經過寄存器edx拷貝原變量的值;
若採用[&]方式,則直接經過ecx拷貝原變量的地址,而不取出值。
閉包內:
pop ecx mov dword ptr [ebp-8],ecx a = 0xA; mov eax,dword ptr [ebp-8] mov ecx,dword ptr [eax] mov dword ptr [ecx],0Ah }; pop edi pop esi pop ebx mov esp,ebp pop ebp ret
對a進行賦值,直接是:
*this = 0xA;
由於事先this就取到了a的地址。
能夠發現,按引用捕獲實際上就如同函數參數傳遞引用,傳遞的是一個地址值,而不建立對象副本(能夠和上一篇文中的內容比較)。
C++11標準中對Lambda表達式的捕獲內容還有一些特定支持,好比能夠以指定的方式捕獲指定的變量:
int main() { int a = 0xB; bool b = true; auto lambda = [&a,b]{ a = b; }; lambda(); return 0; }
上面的代碼對a進行引用捕獲,對b按值捕獲。根據前面分析的結果,能夠預見,a的地址和b的值將被拷貝以供閉包函數使用。
int a = 0xB; mov dword ptr [ebp-8],0Bh bool b = true; mov byte ptr [ebp-11h],1 auto lambda = [&a,b]{ a = b; }; lea eax,[ebp-11h] push eax lea ecx,[ebp-8] push ecx lea ecx,[ebp-24h] call 00222060 lambda(); lea ecx,[ebp-24h] lambda(); call 00221C20 return 0;
調用Lambda以前,先調用複製函數,傳入兩個參數,&a和&b,而this被放在main的[ebp-24h]中。
複製函數或者叫準備函數:
pop ecx mov dword ptr [ebp-8],ecx mov eax,dword ptr [ebp-8] mov ecx,dword ptr [ebp+8] mov dword ptr [eax],ecx mov eax,dword ptr [ebp-8] mov ecx,dword ptr [ebp+0Ch] mov dl,byte ptr [ecx] mov byte ptr [eax+4],dl mov eax,dword ptr [ebp-8] pop edi pop esi pop ebx mov esp,ebp pop ebp ret 8
[eax] 就是 *this,也即a
[eax+4] 就是 *(this+4),也即b
從內存圖能夠清楚的看到,a的地址被記錄,b的值被複制
閉包函數內:
pop ecx mov dword ptr [ebp-8],ecx a = b; mov eax,dword ptr [ebp-8] movzx ecx,byte ptr [eax+4] mov edx,dword ptr [ebp-8] mov eax,dword ptr [edx] mov dword ptr [eax],ecx
b的值是從[eax+4]也即this+4中取出,而a在this中,其實就是:
*(this) = *(this+4);
能夠看到閉包內經過this做爲基址,對閉包外的變量進行偏移訪問。
下一篇中,我將對具備參數和返回值的Lambda表達式進行分析。