C++11(二) 革新:引用折叠与lambda表达式

前言

接上一篇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底层是仿函数对象

捕捉到的变量变成仿函数的成员变量

相关推荐
萨小耶1 小时前
[Java学习日记11】聊聊深拷贝和浅拷贝
java·开发语言·学习
Mr.朱鹏1 小时前
基于 postgres_fdw 的跨库查询方案
java·数据库·spring boot·sql·spring·postgresql
xiaoshuaishuai81 小时前
C# AvaloniaUI‌的IValueConverter
开发语言·c#
敲个大西瓜1 小时前
Java并发实用干货
java
碎碎念_4921 小时前
”二分“高频题型总结:最小最大值、最大最小值、满足条件最小 / 最大
算法·二分
1368木林森1 小时前
【Spring源码17·完结篇】SpringBoot核心注解+高频坑点+失效场景万字全集!收官Spring全家桶源码系列
java·spring boot·后端
南山十一少1 小时前
基于 Quartz 组件在 Spring Boot 框架下的周期任务调度实验
java·spring boot·spring
罗超驿1 小时前
14.LeetCode 438 题解:滑动窗口+哈希表找所有字母异位词
java·算法·leetcode
白驹笙鸣1 小时前
STL allocator作用
开发语言·c++