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

先谈引用

由于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中,返回局部变量是调用的移动构造函数。

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

本文链接:https://rainlin.top/archives/115
转载请注明转载自:https://rainlin.top
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇