(P36-P39)右值和右值引用、右值引用的作用以及使用、未定引用类型的推导、右值引用的传递
文章目錄
- 1.右值
- 2. 右值引用
- 3.性能優(yōu)化
- 4.&& 的特性
- 5.右值引用的傳遞
1.右值
C++11 增加了一個(gè)新的類型,稱為右值引用( R-value reference),標(biāo)記為 &&。
在介紹右值引用類型之前先要了解什么是左值和右值:
- lvalue 是 loactor value 的縮寫,rvalue 是 read value 的縮寫
- 左值是指存儲(chǔ)在內(nèi)存中、有明確存儲(chǔ)地址 (可取地址)的數(shù)據(jù);
- 右值是指可以提供數(shù)據(jù)值的數(shù)據(jù)(不可取地址);
通過描述可以看出,區(qū)分左值與右值的便捷方法是:可以對(duì)表達(dá)式取地址(&)就是左值,否則為右值 。
所有有名字的變量或?qū)ο蠖际亲笾?#xff0c;而右值是匿名的。
- eg:一般情況下,位于 = 前的表達(dá)式為左值,位于 = 后邊的表達(dá)式為右值。
- 也就是說例子中的 a, b 為左值,520,1314 為右值。a=b 是一種特殊情況,在這個(gè)表達(dá)式中 a, b 都是左值,因?yàn)樽兞?b 是可以被取地址的,不能視為右值。
C++11 中右值可以分為兩種:一個(gè)是將亡值( xvalue, expiring value),另一個(gè)則是純右值( prvalue, PureRvalue):
-
純右值:非引用返回的臨時(shí)變量、運(yùn)算表達(dá)式產(chǎn)生的臨時(shí)變量、原始字面量和 lambda 表達(dá)式等
-
將亡值:與右值引用相關(guān)的表達(dá)式,比如,T&& 類型函數(shù)的返回值、 std::move 的返回值等。
-
eg:在上面的語句中,value 是左值,520 是字面量也就是右值。其中 value 可以被引用,但是 520 就不行了,因?yàn)樽置媪慷际怯抑怠?/p>
2. 右值引用
右值引用就是對(duì)一個(gè)右值進(jìn)行引用的類型。因?yàn)橛抑凳悄涿?#xff0c;所以我們只能通過引用的方式找到它。
-
無論聲明左值引用還是右值引用都必須立即進(jìn)行初始化,因?yàn)橐妙愋捅旧聿⒉粨碛兴壎▽?duì)象的內(nèi)存,只是該對(duì)象的一個(gè)別名。
-
通過右值引用的聲明,該右值又“重獲新生”,其生命周期與右值引用類型變量的生命周期一樣,只要該變量還活著,該右值臨時(shí)量將會(huì)一直存活下去。
-
引用的本質(zhì)是:void* const 指針常量
-
eg:
- eg:常量引用:引用的值不能被修改;右值引用需要用右值進(jìn)行初始化;左值初始化右值引用是錯(cuò)誤的
3.性能優(yōu)化
在 C++ 中在進(jìn)行對(duì)象賦值操作的時(shí)候,很多情況下會(huì)發(fā)生對(duì)象之間的深拷貝,如果堆內(nèi)存很大,這個(gè)拷貝的代價(jià)也就非常大,在某些情況下,如果想要避免對(duì)象的深拷貝,就可以使用右值引用進(jìn)行性能的優(yōu)化。
- eg:
- 測(cè)試:
- 解釋:
通過輸出的結(jié)果可以看到調(diào)用 Test t = getObj(); 的時(shí)候調(diào)用拷貝構(gòu)造函數(shù)對(duì)返回的臨時(shí)對(duì)象進(jìn)行了深拷貝得到了對(duì)象 t,在 getObj() 函數(shù)中創(chuàng)建的對(duì)象雖然進(jìn)行了內(nèi)存的申請(qǐng)操作,但是沒有使用就釋放掉了。
如果能夠使用臨時(shí)對(duì)象已經(jīng)申請(qǐng)的資源,既能節(jié)省資源,還能節(jié)省資源申請(qǐng)和釋放的時(shí)間,如果要執(zhí)行這樣的操作就需要使用右值引用了,右值引用具有移動(dòng)語義,移動(dòng)語義可以將資源(堆、系統(tǒng)對(duì)象等)通過淺拷貝從一個(gè)對(duì)象轉(zhuǎn)移到另一個(gè)對(duì)象這樣就能減少不必要的臨時(shí)對(duì)象的創(chuàng)建、拷貝以及銷毀,可以大幅提高 C++ 應(yīng)用程序的性能。
- eg:
-
測(cè)試:
-
解釋:
通過修改,在上面的代碼給 Test 類添加了移動(dòng)構(gòu)造函數(shù)(參數(shù)為右值引用類型),這樣在進(jìn)行 Test t = getObj(); 操作的時(shí)候并沒有調(diào)用拷貝構(gòu)造函數(shù)進(jìn)行深拷貝,而是調(diào)用了移動(dòng)構(gòu)造函數(shù),在這個(gè)函數(shù)中只是進(jìn)行了淺拷貝,沒有對(duì)臨時(shí)對(duì)象進(jìn)行深拷貝,提高了性能。
如果不使用移動(dòng)構(gòu)造,在執(zhí)行 Test t = getObj() 的時(shí)候也是進(jìn)行了淺拷貝,但是當(dāng)臨時(shí)對(duì)象被析構(gòu)的時(shí)候,類成員指針 int* m_num; 指向的內(nèi)存也就被析構(gòu)了,對(duì)象 t 也就無法訪問這塊內(nèi)存地址了。
在測(cè)試程序中 getObj() 的返回值就是一個(gè)將亡值,也就是說是一個(gè)右值,在進(jìn)行賦值操作的時(shí)候如果 = 右邊是一個(gè)右值,那么移動(dòng)構(gòu)造函數(shù)就會(huì)被調(diào)用。移動(dòng)構(gòu)造中使用了右值引用,會(huì)將臨時(shí)對(duì)象中的堆內(nèi)存地址的所有權(quán)轉(zhuǎn)移給對(duì)象t,這塊內(nèi)存被成功續(xù)命,因此在t對(duì)象中還可以繼續(xù)使用這塊內(nèi)存。
對(duì)于需要?jiǎng)討B(tài)申請(qǐng)大量資源的類,應(yīng)該設(shè)計(jì)移動(dòng)構(gòu)造函數(shù),以提高程序效率。需要注意的是,我們一般在提供移動(dòng)構(gòu)造函數(shù)的同時(shí),也會(huì)提供常量左值引用的拷貝構(gòu)造函數(shù),以保證移動(dòng)不成還可以使用拷貝構(gòu)造函數(shù)。
4.&& 的特性
C++ 中,并不是所有情況下 && 都代表是一個(gè)右值引用,具體的場(chǎng)景體現(xiàn)在模板和自動(dòng)類型推導(dǎo)中,
-
如果是模板參數(shù),需要指定為 T&&,如果是自動(dòng)類型推導(dǎo),需要指定為 auto &&,在這兩種場(chǎng)景下 && 被稱作未定的引用類型。
-
另外還有一點(diǎn)需要額外注意,const T&& 表示一個(gè)右值引用,不是未定引用類型
-
eg:在函數(shù)模板中使用 &&
例子中函數(shù)模板進(jìn)行了自動(dòng)類型推導(dǎo),需要通過傳入的實(shí)參來確定參數(shù) param 的實(shí)際類型。
- eg:
由于上述代碼中存在 T&& 或者 auto&& 這種未定引用類型,當(dāng)它作為參數(shù)時(shí),有可能被一個(gè)右值引用初始化,也有可能被一個(gè)左值引用初始化,在進(jìn)行類型推導(dǎo)時(shí)右值引用類型(&&)會(huì)發(fā)生變化,這種變化被稱為引用折疊。
在 C++11 中引用折疊的規(guī)則如下:
-
通過右值推導(dǎo) T&& 或者 auto&& 得到的是一個(gè)右值引用類型
-
通過非右值(右值引用、左值、左值引用、常量右值引用、常量左值引用)推導(dǎo) T&& 或者 auto&& 得到的是一個(gè)左值引用類型
-
eg:
5.右值引用的傳遞
- eg:
-
測(cè)試:
-
解釋:
根據(jù)測(cè)試代碼可以得知,編譯器會(huì)根據(jù)傳入的參數(shù)的類型(左值還是右值)調(diào)用對(duì)應(yīng)的重置函數(shù)(printValue);
函數(shù) forward () 接收的是一個(gè)右值,但是在這個(gè)函數(shù)中調(diào)用函數(shù) printValue () 時(shí),參數(shù) k 變成了一個(gè)命名對(duì)象,編譯器會(huì)將其當(dāng)做左值(當(dāng)成左值引用更好理解些?)來處理。
總結(jié)&&使用:
左值和右值是獨(dú)立于他們的類型的,右值引用類型可能是左值也可能是右值。
編譯器會(huì)將已命名的右值引用視為左值,將未命名的右值引用視為右值。
auto&&或者函數(shù)參數(shù)類型自動(dòng)推導(dǎo)的T&&是一個(gè)未定的引用類型,它可能是左值引用也可能是右值引用類型,這取決于初始化的值類型(上面有例子)。
通過右值推導(dǎo) T&& 或者 auto&& 得到的是一個(gè)右值引用類型,其余都是左值引用類型。
- 參考:右值引用
總結(jié)
以上是生活随笔為你收集整理的(P36-P39)右值和右值引用、右值引用的作用以及使用、未定引用类型的推导、右值引用的传递的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 搜索引擎蜘蛛的功能与应用
- 下一篇: 人工智能方面有什么创业项目_人工智能创业