c++11新特性:lambda

基本形式

lambda表达式的本质就是重载了()运算符的类,这种类通常被称为functor,即行为像函数的类。因此lambda表达式对象其实就是一个匿名的functor。
一个标准的lambda表达式包括:捕获列表、参数列表、mutable指示符、尾置返回类型(->返回类型)和函数体:

1
[capture list] (params list) mutable exception-> return type { function body }
  • capture list:捕获外部变量列表
  • params list:形参列表
  • mutable指示符:用来说用是否可以修改捕获的变量
  • exception:异常设定
  • return type:返回类型
  • function body:函数体

用法

lambda实际上是一个匿名仿函数对象。重载operator()来实现仿函数功能。基本使用方法如下:

1
2
3
4
5
6
7
8
9
int main(){   
int x = 9;
int y = 19;
auto fun = [&x,y](int x, int y){
return x + y;
};
fun(x,y);
return 0;
}

反汇编之后可以看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) disas main
Dump of assembler code for function main():
0x0000000000401569 <+0>: push rbp
0x000000000040156a <+1>: mov rbp,rsp
0x000000000040156d <+4>: sub rsp,0x40
0x0000000000401571 <+8>: call 0x4016f0 <__main>
0x0000000000401576 <+13>: mov DWORD PTR [rbp-0x8],0x9
0x000000000040157d <+20>: mov DWORD PTR [rbp-0x4],0x13
0x0000000000401584 <+27>: lea rax,[rbp-0x8]
0x0000000000401588 <+31>: mov QWORD PTR [rbp-0x20],rax
0x000000000040158c <+35>: mov eax,DWORD PTR [rbp-0x4]
0x000000000040158f <+38>: mov DWORD PTR [rbp-0x18],eax
0x0000000000401592 <+41>: mov edx,DWORD PTR [rbp-0x8]
0x0000000000401595 <+44>: mov ecx,DWORD PTR [rbp-0x4]
0x0000000000401598 <+47>: lea rax,[rbp-0x20]
0x000000000040159c <+51>: mov r8d,ecx
0x000000000040159f <+54>: mov rcx,rax
0x00000000004015a2 <+57>: call 0x401550 <<lambda(int, int)>::operator()(int, int) const>
=> 0x00000000004015a7 <+62>: mov eax,0x0
0x00000000004015ac <+67>: add rsp,0x40
0x00000000004015b0 <+71>: pop rbp
0x00000000004015b1 <+72>: ret
End of assembler dump

看到call的是一个lambda(int,int)::operator()(int,int)const方法。
这个函数的反汇编结果是:

1
2
3
4
5
6
7
8
9
10
11
12
(gdb) disas 0x401550
Dump of assembler code for function <lambda(int, int)>::operator()(int, int) const:
0x0000000000401550 <+0>: push rbp
0x0000000000401551 <+1>: mov rbp,rsp
0x0000000000401554 <+4>: mov QWORD PTR [rbp+0x10],rcx
0x0000000000401558 <+8>: mov DWORD PTR [rbp+0x18],edx
0x000000000040155b <+11>: mov DWORD PTR [rbp+0x20],r8d
0x000000000040155f <+15>: mov edx,DWORD PTR [rbp+0x18]
0x0000000000401562 <+18>: mov eax,DWORD PTR [rbp+0x20]
0x0000000000401565 <+21>: add eax,edx
0x0000000000401567 <+23>: pop rbp
0x0000000000401568 <+24>: ret

捕获形式

捕获形式 说明
[] 不捕获任何外部变量
[变量名, …] 默认以值得形式捕获指定的多个外部变量(用逗号分隔),如果引用捕获,需要显示声明(使用&说明符)
[this] 以值的形式捕获this指针
[=] 以值的形式捕获所有外部变量
[&] 以引用形式捕获所有外部变量
[=, &x] 变量x以引用形式捕获,其余变量以传值形式捕获
[&, x] 变量x以值的形式捕获,其余变量以引用形式捕获
需要注意的事项:
  • 外部变量是在lambda匿名类构造时传入的。并且传入的是外部变量的引用(由于C++的引用本身就是语法糖,反汇编层面看到的是指针,但是结合源码分析不难得出这里应该是引用)。ambda匿名类会将捕获参数中的变量添加到其成员变量中,并设置一个带有该参数引用类型的构造函数,并在构造函数中完成对相应成员变量的赋值。在调用其operator()函数时,如果用到了捕获列表中的局部变量,则从给匿名类对象的成员变量中取出。