C++ 右值引用与左值引用
意義:可以避免無謂的復(fù)制,提高程序的性能。
左值:表達(dá)式結(jié)束后依然存在的持久化對象
右值:表達(dá)式結(jié)束后不再存在的臨時(shí)對象
所有的具名變量和對象都是左值,而右值不具名。
區(qū)分左值和右值的快捷方法:
看能不能對表達(dá)式取地址,如果能則是左值,否則就是右值。
右值分為純右值和將亡值。
純右值是C++98中的右值概念,如非引用函數(shù)返回的臨時(shí)變量;
一些運(yùn)算表達(dá)式,如4+6產(chǎn)生的臨時(shí)變量;不和對象關(guān)聯(lián)的字面量值,
如10,‘s’,true,“hello”等這些不能被取地址的值。
將亡值:c++11中新增的和右值引用相關(guān)的表達(dá)式,這樣的表達(dá)式通常是將要移動(dòng)的對象
T&&函數(shù)返回值,std::move()函數(shù)的返回值等。
將亡值和純右值統(tǒng)一看成右值,不影響使用。
c++98中引用很常見,就是給變量取一個(gè)別名,在c++11中,因?yàn)樵黾恿擞抑狄玫母拍?#xff0c;
所以c++98中的引用都稱為左值引用。
c++11中的右值引用使用&&符號,如
int &&a = 1; int b = 1; int &&c = b; //編譯錯(cuò)誤,不能將左值賦值給一個(gè)右值引用 class A { public:int a; }; A getTemp() {return A(); } A &&a = getTemp(); //getTemp()返回值是右值(臨時(shí)變量)getTemp()返回的右值本來在表達(dá)式語句結(jié)束后,其生命也就該終結(jié)了(臨時(shí)變量),而通過
右值引用,該右值又獲得了新生,其生命周期與右值引用類型變量a的生命一樣,只要a活著,該
右值臨時(shí)變量將會一直存活下去,實(shí)際上就是給臨時(shí)變量去了一個(gè)名字。
a的類型為右值引用類型(int &&),如果從左值和右值的角度區(qū)分它,它實(shí)際上是一個(gè)左值。
因?yàn)榭梢詫λ〉刂?#xff0c;而且它還有名字,是一個(gè)已經(jīng)命名的右值。
所以,左值引用只能綁定左值,右值引用只能綁定右值。常量左值引用是個(gè)特例,它可以算一個(gè)
萬能的引用類型,可以綁定非常量左值,常量左值,右值,而且在綁定右值的時(shí)候,可以像右值引用一樣
將右值的生命期延長,缺點(diǎn)是只能讀不能改。例子如下:
實(shí)際上,我們在很多情況下都使用了常量左值引用這個(gè)功能,例子如下:
class Copyable { public:Copyable() {}Copyable(const Copyable &o){std::cout << "Copied" << std::endl;} };Copyable ReturnRvalue() {return Copyable(); //返回一個(gè)臨時(shí)對象 }void AcceptVal(Copyable a) { } void AcceptRef(const Copyable &a) { }int main() {std::cout<<"pass by value"<<std::endl;AcceptVal(ReturnRvalue()); //應(yīng)該調(diào)用2次拷貝構(gòu)造函數(shù)std::cout<<"pass by reference"<<std::endl;AcceptRef(ReturnRvalue()); //應(yīng)該只調(diào)用一次拷貝構(gòu)造函數(shù) }上述例子運(yùn)行之后,結(jié)果和預(yù)想的不一樣。AcceptVal(ReturnRvalue())需要調(diào)用兩次拷貝構(gòu)造函數(shù),一次在ReturnRvalue()函數(shù)中,構(gòu)造一個(gè)Copyable()對象,返回的時(shí)候會調(diào)用拷貝構(gòu)造函數(shù)生成一個(gè)臨時(shí)對象。在調(diào)用AcceptVal()時(shí),會將這個(gè)對象拷貝給函數(shù)的局部對象a,一共調(diào)用了兩次拷貝構(gòu)造函數(shù)。而AcceptRef()的不同之處在于形參是常量左值引用,它能接收一個(gè)右值,而不需要拷貝。
實(shí)際的結(jié)果是,不管哪種方式,一次拷貝構(gòu)造函數(shù)都沒有調(diào)用。
這是因?yàn)?strong>編譯器開啟了返回值優(yōu)化(RVO/NRVO,RVO,Return Value Optimization返回值優(yōu)化;NRVO,Nameed Return Valude Optimization)。編譯器發(fā)現(xiàn)ReturnRvalue內(nèi)部生成了一個(gè)對象,返回之后還需要生成一個(gè)臨時(shí)對象調(diào)用拷貝構(gòu)造函數(shù),很麻煩,所以直接優(yōu)化成一個(gè)對象,避免拷貝,而這個(gè)臨時(shí)變量又被賦值給了函數(shù)的形參,還是沒必要,這3個(gè)變量都用一個(gè)變量代替了,不需要調(diào)用拷貝構(gòu)造函數(shù)。
為了能夠更好的觀測結(jié)果,可以在編譯的時(shí)候加上-fno-elide-constructors選項(xiàng)(關(guān)閉返回值優(yōu)化),此時(shí)結(jié)果和預(yù)想的一樣。上述的例子是想說明常量左值可以綁定一個(gè)右值,可以減少一次拷貝(使用非常量左值引用會使失敗,因?yàn)镽eturnRvalue()返回的是臨時(shí)對象(右值))。
//g++ test.cpp -o test -fno-elide-constructors總結(jié):T是一個(gè)具體類型
(1)左值引用,使用T&,只能綁定左值
(2)右值引用,使用T&&,只能綁定右值
(3)常量左值,使用conts T&,可以綁定左值和右值。
(4)已命名的右值引用,編譯器會認(rèn)為是左值。
(5)編譯器有返回值優(yōu)化功能,但不可過于依賴。
參考:https://www.jianshu.com/p/d19fc8447eaa
總結(jié)
以上是生活随笔為你收集整理的C++ 右值引用与左值引用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国内WiFi模组厂商盘点及发展分析
- 下一篇: 涂鸦WIFI模组方案(MCU SDK)