在C++11之前,函数的调用是通过函数名来调用的,函数名可以理解为存储函数指针的变量。程序顺序执行函数名,会call函数名存储的函数指针,通过函数指针顺利完成函数调用。(缺点是会造成函数名的call以及函数参数copy的开销。如果函数参数是一个复杂的类的实例,则需要copy甚至是深copy,造成不必要的开销。C++11对此做了相应的优化,这是后话。)
到此C++已经很好的完成了函数的调用。
C++11之后,C++提供了匿名函数调用,即lambda表达式。
如果lambda只是为了提供一个没有名称的函数,不用太在意这个C++11的新特性。lambda真正的作用在于,给C++的函数式编程提供了可能。什么是函数式编程,我对函数式编程的理解是,把一个函数当做变量使用,即这个函数具有变量的一切特征,赋值,作为参数传递等等。函数作为参数传递需要做到“闭包”,即函数带着上下文的状态进行传递,lambda表达式能做到这一点。
闭包的理解:
如图,在实例化类A后,运行代码后a1,a2,a3,a4,a5五个对象,每个对象都有自己的key和value,且值不会改变。如a1(1)固定胡输出2,a2(11)固定输出22,每个对象都把属性固定下来了,这些对象可以作为参数进行传递,这是我理解的闭包。只不过这里的类换成函数,简单来说:函数+状态=闭包。
函数f复制了一份a的值,保存在函数的栈内存中,输入1后输出11。形成了自己的闭包,函数f可以作为变量使用。
函数g取了a的地址,保存在函数的栈中,输入2后输出12。也形成了闭包,也可以作为变量使用。
从代码实现逻辑来看,使用不使用函数式编程都能实现相应的逻辑,为什么要使用函数式编程?我觉得有两点好处:
1,降低了函数调用的开销,配合右值引用使用,能提高函数的执行效率。
2,在不构建对象的情况下,能作为简易的对象使用,减少了new和delete的使用。
3,代码逻辑更加的简单整洁。
捕获lamdba获取上下文变量的一种方式。
1,[]不获取上下文的变量
2,[=]以值得方式捕获上下文的变量,在执行捕获那一刻,复制一份变量到lamdba表达式中,外部的变量如何变化,跟lamdba无关。
3,[&]以引用的方式捕获上下文得变量,捕获得变量会根据外部的变化内部也跟着变化。
4,[a,&b]混合使用值捕获与引用捕获,变量a是值捕获,变量b是引用捕获。
5,[=,&b]除了b是引用捕获,其他都为值捕获。
6,[&,a]除了a是值捕获,其他都是引用捕获。
lamdba在多线程中嵌套使用时,捕获得变量的生命周期以及虚拟地址,会根据所在线程堆栈的变化而变化,所以在多线程嵌套使用lamdba要特别注意,否则即便编译成功,也极易导致crash。