深入理解C++中的左值引用,右值引用

作者: rainlin 分类: 程序语言 发布时间: 2017-12-09 16:55

先谈引用

由于C中的指针过于灵活,容易出错,所以C++引入了引用来减少出错的用法,记得C++ primer中说,引用就是一个变量的别名,在初始化引用后,引用就无法改变再引用到其他的对象了。在遇到类的移动构造函数时,又见识到了右值引用,书上说,右值引用用于引用到临时对象。
那么就存在一些问题了:

  • 这个别名到底是怎么实现的呢?
  • 引用和指针存在什么关系呢?
  • 左值引用和右值引用本质上的区别在哪?

看看汇编实现

对于这些问题,在C++语言层面上,还是难以把握,我们看看汇编层面是如何实现的:

观察上图可以发现,原来引用也是一个变量,其跟指针的行为竟然一样一样的!
可以看到d引用到c,和把c的地址放到指针ptr2中,其操作一模一样,这也就回答了前两个问题:
引用的本质其实就是指针,但在C++中对于这个特殊的指针,做了诸多的限制,在初始化后,就不能再指向其他的对象,既然不能指向其他对象,那么也就没有必要取指针内部的地址了,那么使用引用的时候,其默认就是取内部地址所指向的对象的值,就与直接使用对象的变量名一样。
再观察一下ptr1,可以发现,ptr1是取引用d的地址,然而汇编实现时,是把d的值传给了ptr1,即ptr1指向了c所以对引用取地址,其实等于引用的对象的地址
再来看看右值引用,可以发现右值引用一个很大的特点在于:它可以引用到”寄存器中的值”,当然不真的引用到寄存器,而是它会先把寄存器中的值保存在内存中,然后再引用到它。这个临时开辟的空间并没有像普通变量那样有个变量名,它只有这个引用来指向它。
如图中的,y,g都属于这种情况,这种情况用左值引用是无法办到的。

函数传值


观察上图,可以发现:
在第一次func1中,传入左值对象,调用了拷贝构造函数,生成了临时对象a,然后构造b对象,返回时,由于a对象为临时对象,将调用返回的临时对象的移动构造函数窃取a的资源,最后,析构顺序为,b局部变量,a临时变量,返回的临时变量。
当传入右值对象时,此时生成的临时对象a将调用移动构造函数,窃取传入的右值对象的资源,后续步骤与上类似。
再看func2,由于a是引用对象,所以返回的值对象时调用的拷贝构造函数。
当返回的对象被引用,此时返回的临时对象不会被析构。
再看func3,可以发现,即便以左值引用传递进来,当返回它时,仍然调用的是拷贝构造函数,而func4中,返回局部变量是调用的移动构造函数。

个人认为,对于右值引用,在分析时,应该看具体情况,其本质是为了直接窃取不用的资源,避免重复拷贝构造。

 

 

本文链接: http://rainlin.top/archives/115
转载请注明转载自: Rainlin Home

发表评论

电子邮件地址不会被公开。 必填项已用*标注