前言
接上一篇C++11博客的内容,继续编写
移动构造和移动赋值
左值会走上面这个

右值会走下面这个

这里只有鉴定你的属性是左值,才能移动你右值引用里面的资源
移动构造和移动赋值与拷贝构造和拷贝赋值的核心区别:
只有进行深拷贝的类才考虑移动构造和移动赋值
左值在这里就得老老实实地拷贝,因为都是一些持续存在的值

右值都是一些即将销毁的值(临时对象,匿名对象等),里面的成员不能进行修改,就可以将资源进行掠夺
右值引用的属性是左值

左值引用是直接起作用,传值传参要拷贝,传值返回要拷贝,传引用传参,传引用返回不用拷贝,因为返回的是别名,形参是实参的别名
右值引用是依靠移动语义(移动构造,移动赋值)来起作用,他把右值引用给区分出来,当你要进行右值拷贝的时候,移动其资源
不管怎么样,只要我们写了移动构造和移动赋值,传值返回,直接接收和先定义对象再接收,都没有多大区别,这才是保障


这里使用右值引用会更高效

这里就说明提效了,左值插入拷贝构造代价更高,右值移动构造的代价更低
引用折叠


后来的语法喜欢用using去替代typedef

引用折叠
只要有一个左值引用都是左值引用

函数模板的特点是:实参传给形参去推出T的类型,这里推成左右值都可以折叠

只要我写了T&,不管怎么样都是左值引用

传左值是左值引用,传右值是右值引用

这里是万能引用
传左值就是左值,传右值就是右值

只要是右值,都没有折叠,就只是int
传的是左值就是左值引用

完美转发
这个不是万能引用
因为是类模板的一个成员函数,这个T不是通过实参传形参推的,而是类模板实例化的时候就实例化的


所以就出现了完美转发forward,底层的核心原理还是强制类型转换,但是与move不同,move只能转成右值

如下图,函数中需要将t值再调用一遍的,如果不加入完美转发,就会都是左值属性,因为不管是左值引用还是右值引用,值的本身都是左值属性,打印出来的就全是左值引用
如果使用了完美转发,则可以保持t左值引用的左值引用返回,右值引用的右值引用返回
完美转发forward本质是⼀个函数模板,他主要还是通过引用折叠的方式实现,下面示例中传递给
Function的实参是右值,T被推导为int,没有折叠,forward内部t被强转为右值引用返回;传递给
Function的实参是左值,T被推导为int&,引用折叠为左值引用,forward内部t被强转为左值引用
返回。


int main()
{
// 10是右值,推导出T为int,模板实例化为void Function(int&& t)
Function(10); // 右值
int a;
// a是左值,推导出T为int&,引⽤折叠,模板实例化为void Function(int& t)
Function(a); // 左值
// std::move(a)是右值,推导出T为int,模板实例化为void Function(int&& t)
Function(std::move(a)); // 右值
const int b = 8;
// a是左值,推导出T为const int&,引⽤折叠,模板实例化为void Function(const int&t)
Function(b); // const 左值
// std::move(b)右值,推导出T为const int,模板实例化为void Function(const int&&t)
Function(std::move(b)); // const 右值
return 0;
}
lambda表达式语法
本质是一个匿名函数对象,跟普通函数不同的是它可以定义在函数内部

参数为空可以省略
捕捉为空也不能省略
这里返回值部分可以省略,可以通过返回对象自动推导,写上的话更具有可读性
函数体不可以省略




相比于仿函数的话,lambda表达式需要实现的轻和少(如比大小,仿函数需要实现的就很多,如一个大小需要实现2个仿函数)
lambda不需要取名字,因为本身就是匿名函数对象

捕捉列表

lambda表达式中默认只能用lambda函数体和参数中的变量,如果想用外层作用域中的变量就需要进行捕捉
lambda表达时是可以写在全局的,全局就不需要捕捉,必须为空
局部的静态和全局变量不能捕捉,也不需要捕捉

传值捕捉过来的变量是不可以修改的,就跟被const修饰了一样,是不可以修改的

如果想要修改也是可以,但是这里的++不会影响外面的值,因为传值捕捉始终是拷贝


隐式捕捉
隐式值捕捉
用了哪些就捕捉哪些变量

隐式引用捕捉
用了哪些变量就捕捉哪些变量

混合捕捉


原理
范围for的底层是迭代器,lambda底层是仿函数对象
捕捉到的变量变成仿函数的成员变量
