【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

这篇具有很好参考价值的文章主要介绍了【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 统一的列表初始化

{ } 初始化

C++11 扩大了括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义类型,
使用初始化列表,可添加等号(=),也可不添加

【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

将1赋值给x1,x2处省略了赋值符号,将5赋值给x2
同样也可以将new开辟4个int的空间初始化为0


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

创建对象时,可以使用列表初始化方式调用构造函数初始化,也可省略等号

initializer_list

【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

花括号里面的常量数组,C++可以将其识别成一个类型 initializer_list,
initializer_list这个类带有模板参数,因为传过来的int数据,所以为 initializer_list


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

类中存在两个指针
size作为两个指针相减
begin指向开始的位置,end 指向结束位置的下一个


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

对数据不能修改,说明指向的内容在常量区
任意的常量数组 都可以赋值给 initializer_list的对象


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

C++11中 的vector,是 通过新增的构造函数的方式 使用 initializer_list 进行初始化

2. 引用

左值引用

左值引用就是给左值取别名
左值是一个数据的表达式(如变量名或者引用指针)
可以获取它的地址 即为左值


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

左值出现赋值符号的左边 (也可出现在右边)


右值引用

【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

右值也是一个表示数据的表达式(如字面常量、表达式返回值、函数返回值)
右值可以出现在赋值符号的右边,但不能出现赋值符号的左边,右值不能取地址

右值引用 就是 给右值起别名


左值引用与右值引用的相互转换

【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

x+y 作为右值 ,左值引用是无法直接引用右值的
但可以通过隐式类型转换的方式,由于 临时变量具有常性, 加入 const 即可


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

a作为左值, 右值引用是无法直接引用左值, 使用move 后,其返回值作为右值

右值引用的真正使用场景

【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

虽然可以在左值中加入const ,既可以使用左值 ,又可以使用右值
但是 无法区分到底是左值还是右值的


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

加入右值引用后,传参过程中,更好的进行参数匹配
就可以 区分 是调用 左值引用 还是 右值引用


移动构造

右值分为两种
1.纯右值(内置类型)
2.将亡值(自定义类型)


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

s1作为左值,调用拷贝构造
s1+s2 作为表达式返回值,代表右值 即 将亡值


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

若右值进行深拷贝,(再创建一块空间在原有的数据拷贝过来,然后释放原有空间),
将亡值 是没有必要拷贝,代价太大了


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发
由于有const,所以无论是左值还是右值都可以传过来作为参数


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

将右值(将亡值) 的资源进行转移ret2
使用右值引用 区分出右值后,就没有必要进行深拷贝了 ,
接收右值 作为参数 的拷贝 称为 移动拷贝


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发
调用移动构造,进行移动拷贝


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发
右值就不再调用深拷贝,而是使用移动拷贝

C++98与C++11传值返回问题

【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发
对于传值返回,C++98 刚开始会进行两次拷贝构造,
编译器优化后,会进行一次拷贝构造


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

编译器不优化时
str作为临时变量 属于左值, 将str传给 临时变量 ,属于拷贝构造
临时对象 是看不见摸不着的 无法知道它的地址 ,所以属于 右值 (将亡值) ,
所以将右值传给 str ,属于 移动构造

编译器优化时
编译器会想办法将 函数中的临时变量 str 识别成 右值(使用move其函数返回值为右值),进行移动构造 (资源转移)


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发
s2 进行深拷贝 ,将s1的数据拷贝到新开辟的空间中
move(s1)后,表达式返回值作为右值
s3 进行移动拷贝,把s1的资源转移到s3中,所以导致s1为空

注意事项

【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

右值是不可以取地址的,但是给右值取别名后,会导致右值存储到特定位置,并且可以取到该位置地址
如:不能取到字面常量10的地址,但是ret引用后,可以对ret取地址,也可以修改ret,如果像ret不能修改,需要加入const 即 const int &&

总结

左值引用减少拷贝,提高效率
右值引用也是减少拷贝,提高效率
但角度不同,
左值引用是直接减少拷贝
右值引用是间接减少拷贝,识别出是左值还是右值,若识别出是右值,则不再深拷贝,
直接移动拷贝(资源转移),提高效率

3. 完美转发

【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

写一个函数 ,无论传过来的参数为左值还是右值,都可以接受 (将左值move后,返回值为右值)

当左值作为参数 时, 会发生引用折叠,调用 fun(t),此时t作为左值,所以会输出 左值引用


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

当右值作为参数时,实际上右值接收后,要进行移动拷贝,右值引用 引用后属性会变成左值,否则无法进行资源转移


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

调用push_back ,参数为右值,右值引用 引用后属性会变成左值,但是 变为左值为了进行 资源转移的 ,
还没等进行转移, 在这期间先调用 insert ,(x作为左值),调用左值引用的insert 就会导致 进行深拷贝,而不是进行移动拷贝


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

C++支持 完美转发 ,用于保持原有的属性,避免 参数x在资源转移之前 转过早的情况


【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发

所以当此时fun 参数 加入forward 完美转发后,使右值 引用后,并没有立即变为左值,而是保持原有的属性 右值
所以 调用 对应的fun 打印 右值引用
文章来源地址https://www.toymoban.com/news/detail-477056.html

到了这里,关于【C++11】 initializer_list | 右值引用 | 移动构造 | 完美转发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】—— C++11新特性之 “右值引用和移动语义”

    前言: 本期,我们将要的介绍有关 C++右值引用 的相关知识。对于本期知识内容,大家是必须要能够掌握的,在面试中是属于重点考察对象。 目录 (一)左值引用和右值引用 1、什么是左值?什么是左值引用? 2、什么是右值?什么是右值引用? (二)左值引用与右值引用比

    2024年02月11日
    浏览(43)
  • 【C++】 C++11(右值引用,移动语义,bind,包装器,lambda,线程库)

    C++11是C++语言的一次重大更新版本,于2011年发布,它包含了一些非常有用的新特性,为开发人员提供了更好的编程工具和更好的编程体验,使得编写高效、可维护、安全的代码更加容易。 一些C++11的新增特性包括: 强制类型枚举,使得枚举类型的通常行为更加可靠和容易控制

    2024年02月10日
    浏览(44)
  • std::initializer_list详解

    initializer_list是C++11提供的一种新类型,其定义于头文件initializer_list中,此头文件是工具库的一部分, initializer_list定义如下:   std::initializer_list 类型对象是一个访问 const T 类型对象数组的轻量代理对象。 std::initializer_list 对象在这些时候自动构造: 用花括号初始化器列表列

    2024年02月07日
    浏览(41)
  • 【C++进阶知识】04 - 函数默认实参、默认初始化、initializer_list

    默认实参需要注意以下几点: (1)函数默认实参的赋值应从右往左,否则编译报错,因为参数入栈应该从右往左。 (2)类外的默认实参会使类的非默认构造函数变成默认构造函数。 (3)如果在类中添加了该函数的该参数的默认实参,那么在类外再次定义该参数的默认实参

    2024年02月14日
    浏览(44)
  • c++右值引用、移动语义、完美转发

    左值:一般指的是在内存中有对应的存储单元的值,最常见的就是程序中创建的变量 右值:和左值相反,一般指的是没有对应存储单元的值(寄存器中的立即数,中间结果等),例如一个常量,或者表达式计算的临时变量 左值引用:C++中采用 对变量进行引用,这种常规的引

    2024年02月05日
    浏览(55)
  • c++积累8-右值引用、移动语义

    1.1 背景 c++98中的引用很常见,就是给变量取个别名,具体可以参考c++积累7 在c++11中,增加了右值引用的概念,所以c++98中的引用都称为左值引用 1.2 定义 右值引用就是给右值取个名字,右值有了名字之后就成了普通变量,可以像使用左值一样使用。 语法:数据类型 变量名

    2023年04月23日
    浏览(38)
  • C++右值引用(左值表达式、右值表达式)(移动语义、完美转发(右值引用+std::forward))(有问题悬而未决)

    在 C++ 中,表达式可以分为左值表达式和右值表达式。左值表达式指的是可以出现在赋值语句左边的表达式,例如变量、数组元素、结构体成员等;右值表达式指的是不能出现在赋值语句左边的表达式,例如常量、临时对象、函数返回值等。 右值是指将要被销毁的临时对象或

    2024年02月04日
    浏览(45)
  • C++ Primer阅读笔记--对象移动(右值引用、移动迭代器和引用限定符的使用)

    目录 1--右值引用 2--std::move 3--移动构造函数 4--移动赋值运算符 5--移动迭代器 6--引用限定符         右值引用必须绑定到右值的引用,通过 获得右值引用;         右值引用只能绑定到 临时对象 (即将被销毁的对象),即所引用的对象将要被销毁,对象没有其他用户;

    2024年02月10日
    浏览(37)
  • 【C++11】左值引用和右值引用

    需要云服务器等云产品来学习Linux的同学可以移步/--腾讯云--/--阿里云--/--华为云--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。     目录 一、新的类功能 1、新的默认成员函数 2、类成员变量初始化 3、强制生成默认函数的default 4、禁止生成默认函

    2023年04月17日
    浏览(49)
  • 【送书】【C++11】左值引用和右值引用

    需要云服务器等云产品来学习Linux的同学可以移步/--腾讯云--/--阿里云--/--华为云--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。     目录 一、新的类功能 1、新的默认成员函数 2、类成员变量初始化 3、强制生成默认函数的default 4、禁止生成默认函

    2023年04月09日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包