C 右值引用與左值引用

2021-10-07 07:23:05 字數 2626 閱讀 8275

意義:可以避免無謂的複製,提高程式的效能。

左值:表示式結束後依然存在的持久化物件

右值:表示式結束後不再存在的臨時物件

所有的具名變數和物件都是左值,而右值不具名。

區分左值和右值的快捷方法:

看能不能對表示式取位址,如果能則是左值,否則就是右值。

右值分為純右值和將亡值。

純右值是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 中,乙個變數是左值還是...