日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ 右值引用与左值引用

發布時間:2024/3/26 c/c++ 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ 右值引用与左值引用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

意義:可以避免無謂的復制,提高程序的性能。

左值:表達式結束后依然存在的持久化對象
右值:表達式結束后不再存在的臨時對象

所有的具名變量和對象都是左值,而右值不具名。
區分左值和右值的快捷方法:
看能不能對表達式取地址,如果能則是左值,否則就是右值。

右值分為純右值和將亡值。
純右值是C++98中的右值概念,如非引用函數返回的臨時變量;
一些運算表達式,如4+6產生的臨時變量;不和對象關聯的字面量值,
如10,‘s’,true,“hello”等這些不能被取地址的值。

將亡值:c++11中新增的和右值引用相關的表達式,這樣的表達式通常是將要移動的對象
T&&函數返回值,std::move()函數的返回值等。
將亡值和純右值統一看成右值,不影響使用。

c++98中引用很常見,就是給變量取一個別名,在c++11中,因為增加了右值引用的概念,
所以c++98中的引用都稱為左值引用。

int a = 10; int &refA = a; int &b = 1; //編譯錯誤,1是右值,不能使用左值引用

c++11中的右值引用使用&&符號,如

int &&a = 1; int b = 1; int &&c = b; //編譯錯誤,不能將左值賦值給一個右值引用 class A { public:int a; }; A getTemp() {return A(); } A &&a = getTemp(); //getTemp()返回值是右值(臨時變量)

getTemp()返回的右值本來在表達式語句結束后,其生命也就該終結了(臨時變量),而通過
右值引用,該右值又獲得了新生,其生命周期與右值引用類型變量a的生命一樣,只要a活著,該
右值臨時變量將會一直存活下去,實際上就是給臨時變量去了一個名字。

a的類型為右值引用類型(int &&),如果從左值和右值的角度區分它,它實際上是一個左值。
因為可以對它取地址,而且它還有名字,是一個已經命名的右值。

所以,左值引用只能綁定左值,右值引用只能綁定右值。常量左值引用是個特例,它可以算一個
萬能的引用類型,可以綁定非常量左值,常量左值,右值,而且在綁定右值的時候,可以像右值引用一樣
將右值的生命期延長,缺點是只能讀不能改。例子如下:

const int &a = 1; //常量左值引用綁定右值,不會報錯 class A { public:int a; }; A getTemp() {return A(); } const A &a =getTemp(); //不會報錯,而A& a會報錯

實際上,我們在很多情況下都使用了常量左值引用這個功能,例子如下:

class Copyable { public:Copyable() {}Copyable(const Copyable &o){std::cout << "Copied" << std::endl;} };Copyable ReturnRvalue() {return Copyable(); //返回一個臨時對象 }void AcceptVal(Copyable a) { } void AcceptRef(const Copyable &a) { }int main() {std::cout<<"pass by value"<<std::endl;AcceptVal(ReturnRvalue()); //應該調用2次拷貝構造函數std::cout<<"pass by reference"<<std::endl;AcceptRef(ReturnRvalue()); //應該只調用一次拷貝構造函數 }

上述例子運行之后,結果和預想的不一樣。AcceptVal(ReturnRvalue())需要調用兩次拷貝構造函數,一次在ReturnRvalue()函數中,構造一個Copyable()對象,返回的時候會調用拷貝構造函數生成一個臨時對象。在調用AcceptVal()時,會將這個對象拷貝給函數的局部對象a,一共調用了兩次拷貝構造函數。而AcceptRef()的不同之處在于形參是常量左值引用,它能接收一個右值,而不需要拷貝。

實際的結果是,不管哪種方式,一次拷貝構造函數都沒有調用。

這是因為編譯器開啟了返回值優化(RVO/NRVO,RVO,Return Value Optimization返回值優化;NRVO,Nameed Return Valude Optimization)。編譯器發現ReturnRvalue內部生成了一個對象,返回之后還需要生成一個臨時對象調用拷貝構造函數,很麻煩,所以直接優化成一個對象,避免拷貝,而這個臨時變量又被賦值給了函數的形參,還是沒必要,這3個變量都用一個變量代替了,不需要調用拷貝構造函數。

為了能夠更好的觀測結果,可以在編譯的時候加上-fno-elide-constructors選項(關閉返回值優化),此時結果和預想的一樣。上述的例子是想說明常量左值可以綁定一個右值,可以減少一次拷貝(使用非常量左值引用會使失敗,因為ReturnRvalue()返回的是臨時對象(右值))。

//g++ test.cpp -o test -fno-elide-constructors

總結:T是一個具體類型

(1)左值引用,使用T&,只能綁定左值

(2)右值引用,使用T&&,只能綁定右值

(3)常量左值,使用conts T&,可以綁定左值和右值。

(4)已命名的右值引用,編譯器會認為是左值。

(5)編譯器有返回值優化功能,但不可過于依賴。

參考:https://www.jianshu.com/p/d19fc8447eaa

總結

以上是生活随笔為你收集整理的C++ 右值引用与左值引用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。