【C++11lambda表达式
@TOC
- 为什么要有lambda表达式存在?
以商品举例,可以通过名字 排序,可以通过价格排序,可以通过评价排序
在C++中,使用仿函数可以进行 价格的比较 若不看仿函数具体实现,则无法通过仿函数对象 来知道 该仿函数到底是怎么比较的 所以就提出了lambda表达式
- lambda表达式的基本语法
1.[capture-list] :
捕捉列表
该列表出现在lambda的开始位置 捕捉列表可以捕捉上下文变量供 lambda函数使用 不可省略,若不进行任何捕捉,则写成 []
2.(paraments) :参数列表
与函数的参数列表相同
若没有参数,可以将()省略
3.mutable:异变
(后面会详细说)
4.-> return- type :返回值类型
可省略,编译器会对返回类型进行推导
5.{statement} :函数体
在函数体内部,除了使用其参数外,还可用捕捉的变量
基本使用

捕捉列表:不可省略,若不进行任何捕捉,则写成 [] 参数列表:存在两个参数 x 和 y 异变:不使用时,可省略 返回值类型:是可以省略的,编译器会自动推导 (但一般不建议省略) 函数体:要注意内部是要有分号的,代表语句结束
表达式整体代表一个lambda对象,是可以被调用的

将返回值类型省略,编译器可以自动推导

通过lambda表达式 即可清楚了解 lambda表达式对象内部如何实现比较的
若想修改升序或降序,只需修改对应的lambda表达式代码即可
捕捉列表和异变的使用
若不进行任何捕捉,使用lambda表达式完成交换

传值捕捉
若想用外面域的变量,则需要捕捉, 捕捉多个值,用逗号分割

由于是传值捕捉,所以捕捉过来的a和b是外面的拷贝,是无法改变的
异变的使用

加入mutable 异变
,即可修改传值捕捉所过来的a和b
但是无法完成交换,传值捕捉所进行的修改,并不会影响 本身
引用捕捉

使用引用的方式,即可通过修改捕捉后的a和b,来影响本身 的值进行修改
混合捕捉

a引用捕捉,b传值捕捉

假设有一堆的变量,不想一个一个捕捉 使用 [&] 即全部使用引用捕捉

使用 [=] 即全部使用传值捕捉

除了a使用传值捕捉以外,其他全部使用引用捕捉
- 线程与lambda表达式之间的关系
pthread库是 POSIX线程库,POISIX(可移植操作系统接口) windows 与linux 下的库是不一样的
C++11中,linux和windows下都支持多线程程序 即 使用
thread库

第一个参数 作为模板类型,所以可以是 函数指针 、仿函数对象 或 lambda对象 为可调用的对象即可
对于第二个参数 Args&&....args来说 通过模板的可变参数,想传几个参数都可以 使用万能引用,当为左值时,发生引用折叠,即可以看作是& ,调用深拷贝 当为右值时,发生移动构造,进行资源转移

对于thread库的调用,与linux中的pthread库大部分功能都是类似的, 如:join 与 pthread_jojn 功能相同 ,线程等待 若一个新线程被创建出来,需要主线程就等待的 detach 与pthread_detach 功能相同,线程分离 默认是阻塞的 ,即主线程等待 新线程退出,主线程 想做其他事情
线程与lambda的结合使用

使用lambda对象 作为可被调用对象 通过lambda表达式对象, 先将 a进行传值捕捉,将1作为sum ,再进行循环 再将 b进行传值捕捉,将2作为sum,再进行循环
将m个线程打印n次

允许移动赋值

每次都创建一个线程,其整体可以看作是一个匿名对象,属于右值,所以进行移动赋值 将新建线程的资源转移到线程数组中
- lambda原理
一个 lambda对象有多大?
实际上是1字节
转化为汇编探究
编译器会把lambda处理成仿函数

先查看仿函数的汇编


先调用构造函数,使r1成为仿函数对象 再调用rate类中的operator()
再查看lambda的汇编

由编译器生成一个不重复的类,(保证每个lambda都不一样),用该类调用构造函数 以及 调用类中的 operator()
仿函数汇编的调用与lambda汇编的调用都是先调用构造函数,在调用operator(),说明lambda底层就为仿函数实现的
根据仿函数,生成仿函数的类,由于仿函数的类是空类 ,所以为1字节 即lambda对象为1字节