【c++】右值引用

一、左值和右值

所有的c++表达,不是左值就是右值。

左值是指存在于单个表达式之外的对象(如变量),而右值则是暂时存在于单个表达式之内的对象(如字面常量、函数或表达式的返回值)。通俗来说就是,左值的生存期不只是当前表达式,后面还能用到它;而右值出了当前表达式就挂了,又称为将亡值。

左值在内存中占有确定的地址,可以获取它的地址,可以对它进行赋值,左值可以在赋值符号的左边或者右边。右值不在内存中占有确定地址(不是不占地址,只是我们找不到),不可以获取它的地址,通常是不可改变的值,它只能在赋值符号的右边。

二、左值引用和右值引用
(1)概念

左值引用就是给左值取别名,右值引用就是给右值取别名。

左值引用:只能引用左值,就是我们通常使用的引用

const 左值引用:可以引用左值,也可以引用右值(因为右值通常是不可改变的值)

右值引用:只能引用右值,左值可以通过move(左值)转换为右值,继而使用右值引用

                  右值引用是左值,可以取地址、可以修改值

const右值引用:如果想限制右值引用不被修改,可以加const修饰

int main() {
	// 左值引用只能引用左值,不能引用右值。
	int a = 10;
	int& ra1 = a;   // ra1为a的别名
	//int& ra2 = 10;   // 编译失败,因为10是右值
 
	// const左值引用既可引用左值,也可引用右值。
	const int& ra3 = 10;
	const int& ra4 = a;
 
	 //右值引用只能右值,不能引用左值。
	int&& r1 = 10;

	int a = 10;
    //message : 无法将左值绑定到右值引用
	int&& r2 = a; 

	 //右值引用可以引用move以后的左值
	int&& r3 = std::move(a);

    ++r1;

    const double&& rr2 = 10;
	//rr2++;  //不可以修改

	return 0;
}
(2)作用和价值

左值引用的意义在于:

1、函数传参:引用传递可以避免实参传递给形参时发生拷贝

2、函数返回值:对于出了作用域还存在的对象,同样可以通过返回引用类型避免拷贝

但函数传返回值时,对于出了作用域就销毁的对象,左值引用不能解决问题。此时有两种方式可以避免拷贝:使用输出型参数和右值引用。

对于出了作用域就销毁的对象,函数传返回值时,会发生两次拷贝构造(return时先将返回值拷贝给一个临时变量,再由临时变量拷贝给函数返回值的赋值对象)。有的编译器会自动优化,将连续的两个拷贝构造优化为一个,直接跳过中间的临时变量。

右值引用可以补齐函数传返回值时发生拷贝构造的短板:

传左值时,会调用拷贝构造函数。

传右值时,会调用移动构造函数,移动构造函数会直接将this和右值(将亡值)交换资源。

有了移动构造之后,函数返回右值(move(左值)),可以实现0拷贝。

上述是针对拷贝初始化,对于拷贝赋值,是用一个已存在的对象接受返回值,此时编译器无法进行优化,需要中间生成一个临时变量。此时函数返回右值,会先调用移动构造生成一个临时变量,然后再调用移动赋值将临时变量赋值给已存在的对象。

区分:直接初始化(一般使用 ( ) 来定义对象)、拷贝初始化(一般使用 = 来定义对象)和拷贝赋值(对已经初始化完成的对象进行修改)

一句话理解精髓就是,由于左值还要继续使用,所以我们只能对其进行拷贝构造;而右值是将亡值,我们可以直接对其进行资源交换,从而避免拷贝。

三、万能引用和完美转发

对于参数类型是右值引用的函数,我们在传右值时,右值引用会改变右值的特性,将其变为左值。如果我们想要继续调用右值引用的函数,则需要不断的move将左值转化为右值。

万能引用:当不明确规定传左值还是右值时,万能引用起到了用处,可以随便传入左值或右值。参数中的&&不是右值引用,而是为了万能引用,可以折叠。当传左值时,就把&&折叠为&。

// 万能引用
template<typename T>
void PerfectForward(T&& t) {
  // t 可能是左值也可能是右值
  // func(move(t));

  // 完美转发,保持属性
  func(std::forward<T>(t));
}

走到调用Func()时,还是会因为由于右值引用导致右值转化为左值,所以又引出了完美转发,完美转发可以自动识别我们传的是左值还是右值,并保持属性,不会因为右值引用而改变右值属性。

参考:https://blog.csdn.net/ChaoFreeandeasy_/article/details/130229252

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++11中,引用的作用之一是实现移动语义,即对象的资源所有权的转移。在C++11之前,移动语义的缺失是C++所面临的一个问题。引用也可以看作是一块空间的别名,只能引用。通过使用引用,我们可以对进行引用,并且可以实现对移动语义的支持。引用的语法是在类型后面加上两个&&。在函数返回为临时变量的情况下,可以使用引用来接收该临时变量。另外,引用还可以引用经过move操作后的左,通过使用move函数,可以改变左的属性,使其变成。总之,引用C++中的作用主要是支持移动语义,提高程序的性能和效率。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [c++引用具体用法](https://download.csdn.net/download/weixin_38734492/14887141)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [C++11——引用](https://blog.csdn.net/weixin_57023347/article/details/120957689)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值