右值引用,移动语义,完美转发
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了右值引用,移动语义,完美转发相关的知识,希望对你有一定的参考价值。
参考技术A c++中有左值与右值的概念一般认为可以取地址的是左值,反之是右值
通常我们可以像这样定义一个引用
int a=1;int &b=a;
此时引用指向一个左值,该引用是一个左值引用
如果使用int &b=1;就会报错
c++还允许使用引用指向右值,即所谓的右值引用
class A;
int &&b=1;
int &&c=A();//指向一个A类的临时变量
右值引用延长了临时变量的生存时间
首先回到我们使用左值引用的场景
很多时候我们会将引用作为函数的参数,这样就可以避免调用构造函数,然而这样的方式不适用于
传入一个临时变量
因为1是右值
右值引用使得我们可以传入一个临时变量作为实参。
因为临时变量生存时间很短,实际上每次用完马上就销毁是比较浪费资源的,使用右值引用既可以解决值传递浪费资源的问题,又突破了左值引用只能传左值的限制
通常的复制构造函数是进行一个深拷贝,而移动构造函数是用自己的指针直接指向被复制对象的指针,看上去就像浅拷贝一样,但是他会将被复制对象的指针归零。是一个抢占指针的过程,避免了浅拷贝可能导致的指针悬挂。在很多时候移动构造函数避免了复制构造函数带来的额外的开销。
move可以将一个左值转为右值
还记得前面提到的右值引用本身是左值吗
这就导致了,当传入一个右值给右值引用作为参数后,右值引用这个形参本身是左值,当他在作为实参调用其他函数时调用的是左值作为参数的函数。这就产生了不完美转发。
如何解决:
调用forward函数,forward函数会将其转为右值
C++ 专题 右值引用移动语义与完美转发
这三个概念都是c++11引入的概念,在此总结一些粗浅的理解。
右值与左值
- 右值是什么(左值)
应该在c++98就有左右值的概念吧(不确定我也懒得调研啊)。
所谓左值右值,左值取址(地址),右值取值(数值)Lvalue = expressions of which we can get memory address
Rvalues = expressions of which we can\'t get memory address
左值refer to 内存中的某一具名对象,比如变量、函数参数、类对象
右值主要是临时对象,比如literals(字面值)、操作的临时结果(a+b), 函数非引用返回的临时对象,匿名对象... - 为什么要有右值
以下内容来自某乎某高赞答案,为防止失效,除了链接直接把原文也抄了过来
可是实现上为了即便是右值表达式为了求出其值依然需要分配一块内存来存放这个值,这形成了一个临时对象,即使之后没有给这个对象取名,对象依然形成了,依然经历了构造和析构的完整生命周期。
这是C++支持RAII之后的事情了。而且即便现在基本类型的右值表达式并不需要事先分配内存。
左右并非是C/C++才开始有的,而是当前计算机体系结构的客观现实。本来,左值是内存上的变量(有地址),右值是只在寄存器当中存在的值(没有地址)。
这样就好理解了吧。只不过有了结构体和对象概念之后,单个数据类型也可能大到无法完整存放在寄存器当中,需要在栈或者堆(反正都是内存)上开额外空间临时存放。再加上RAII的要求,所以才把事情搞那么绕,那么复杂。
其实若把这个临时空间(scratch memory)看作寄存器的扩展,不属于常规内存,那么就好理解了。事实上C++从语法规定上禁止对右值取地址,即便它在内存上有位置。这就是告诉你,这片内存并不是通常的内存,逻辑上它只是超大寄存器。
https://www.zhihu.com/questio...
右值引用(与左值引用)
ok,右值可以理解,那右值引用是什么鬼?为什么要refer一块在内存上但是没法取地址访问的东西。c++98
中的引用很常见了,就是给变量取了个别名,我们可以通过解引用获取到变量(对象),实际上这具体指的是左值引用
以上是关于右值引用,移动语义,完美转发的主要内容,如果未能解决你的问题,请参考以下文章
C++11的右值引用移动语义(std::move)和完美转发(std::forward)详解