意義:可以避免無謂的複製,提高程式的效能。
左值:表示式結束後依然存在的持久化物件
右值:表示式結束後不再存在的臨時物件
所有的具名變數和物件都是左值,而右值不具名。
區分左值和右值的快捷方法:
看能不能對表示式取位址,如果能則是左值,否則就是右值。
右值分為純右值和將亡值。
純右值是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
;a gettemp()
a &&a = gettemp(); //gettemp()返回值是右值(臨時變數)
gettemp()返回的右值本來在表示式語句結束後,其生命也就該終結了(臨時變數),而通過
右值引用,該右值又獲得了新生,其生命週期與右值引用型別變數a的生命一樣,只要a活著,該
右值臨時變數將會一直存活下去,實際上就是給臨時變數去了乙個名字。
a的型別為右值引用型別(int &&),如果從左值和右值的角度區分它,它實際上是乙個左值。
因為可以對它取位址,而且它還有名字,是乙個已經命名的右值。
所以,左值引用只能繫結左值,右值引用只能繫結右值。常量左值引用是個特例,它可以算乙個
萬能的引用型別,可以繫結非常量左值,常量左值,右值,而且在繫結右值的時候,可以像右值引用一樣
將右值的生命期延長,缺點是只能讀不能改。例子如下:
const int &a = 1; //常量左值引用繫結右值,不會報錯
class a
;a gettemp()
const a &a =gettemp(); //不會報錯,而a& a會報錯
實際上,我們在很多情況下都使用了常量左值引用這個功能,例子如下:
class copyable
copyable(const copyable &o)
};copyable returnrvalue()
void acceptval(copyable a)
void acceptref(const copyable &a)
int main()
{ std::cout<<"pass by value"《上述例子執行之後,結果和預想的不一樣。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)編譯器有返回值優化功能,但不可過於依賴。
c 左值 右值 右值引用 左值引用
c 裡一切值必須屬於左值 右值兩者之一。左值 一切變數 包括用const修飾的變數 物件 包括引用都屬於左值 右值 一切字面值 可以是巨集 臨時無名物件 函式返回值 表示式 如a n 說明一下 函式返回值,返回的是某乙個型別的值,並不是返回變數。左值並不是說能放在 左邊的值就是左值 雖然用const...
c 左值 右值 左值引用 右值引用
在c語言中,左值認為是賦值語句的左側,右值認為是賦值語句的右側。在c 中,意義稍有不同。c 中,每乙個表示式會產生乙個左值或者右值,相應的,該表示式也就被稱作 左值表示式 右值表示式 乙個左值表示式的求值結果是乙個物件或者是乙個函式。左值可以當右值使用,而右值不能當左值使用。c prime 中這麼簡...
C 左值 右值 左值引用 右值引用
就變數而言,對於一些變數,我們只會讀取並使用它們的值,而不會改變他們的值 唯讀 對於其餘的變數,我們既會讀取它們的值,有的時候還會改變它們的值 讀寫 這是很常見的。在c 中,前一種變數稱為右值,後一種變數稱為左值,例如 int a 1 a是左值,1是右值稍稍不同的一點是,在c 中,乙個變數是左值還是...