C++:淺談右值引用
1.什麼是左值和右值?
C/C++語言中可以放在賦值符號左邊的變數,即具有對應的可以由使用者訪問的儲存單元,並且能夠由使用者去改變其值的量。左值表示儲存在計算機記憶體的物件,而不是常量或計算的結果。或者說左值是代表一個記憶體地址值,並且通過這個記憶體地址,就可以對記憶體進行讀並且寫(主要是能寫)操作;這也就是為什麼左值可以被賦值的原因了。相對應的還有右值:當一個符號或者常量放在操作符右邊的時候,計算機就讀取他們的“右值”,也就是其代表的真實值。
簡單來說就是,左值相當於地址值,右值相當於資料值。右值指的是引用了一個儲存在某個記憶體地址裡的資料。
左值右值翻譯:
L-value中的L指的是Location,表示可定址。Avalue (computer science)that has an address.
R-value中的R指的是Read,表示可讀。in computer science, a value that does not have an address in a computer language.
左值和右值是相對於賦值表示式而言的。左值是能出現在賦值表示式左邊的表示式。左值表示式可以分為可讀寫的左值和只讀左值。右值是可以出現在賦值表示式右邊的表示式,他可以是不佔據記憶體空間的臨時量或字面量,可以是不具有寫入權的空間實體。如
int a=3;
const int b=5;
a=b+2; //a是左值,b+2是右值
b=a+2; //錯!b是隻讀的左值但無寫入權,不能出現在賦值符號左邊
(a=4)+=28; //a=4是左值表示式,28是右值,+=為賦值操作符
34=a+2; //錯!34是字面量不能做左值
1
2
3
4
5
6
2.右值引用
為了支援移動操作,c++新標準引入了一種新的引用型別—右值引用。所謂右值引用就是必須繫結到右值的引用。我們通過&&而不是&來獲得右值引用。如我們將要看到的,右值引用有一個重要的性質—只能繫結到一個將要銷燬的物件。 因此,我們可以自由地將一個右值引用的資源“移動”到另一個物件中。
一般而言,一個左值表示式表示的是一個物件的身份,而一個右值表示式表示的是物件的值。
舉例說明:
int i=42;
int &r=i; //正確,r引用i
int &&rr=i //錯誤,不能將一個右值引用繫結到一個左值上
int &r2=i*42; //錯誤,i*42是一個右值
const int &r3=i*42; //正確,我們可以將一個const的引用繫結到一個右值上
int &&r2=i*42; //正確,將rr2繫結到乘法結果上
1
2
3
4
5
6
1.左值持久,右值短暫
左值有持久的狀態,而右值要麼是字面值常量,要麼是表示式求值過程中建立的臨時物件。
由於右值引用只能繫結到臨時物件,我們得知
1.所引用的物件將要被銷燬
2,.該物件沒有其他使用者
這兩個特徵意味著:使用右值引用的程式碼可以自由地接管所引用的物件的資源。
2.變數是左值
變數可以看作只有一個運算物件而沒有運算子的表示式,雖然我們很少這樣看待變數。類似於其他任何表示式,變量表達式也有左值/右值屬性。變量表達式都是左值,帶來的結果就是,我們不能將一個右值引用繫結到一個右值引用型別的變數上。
int &&rr1 =42; //正確,字面值常量是右值
int &&r2 =rr1; //錯誤,表示式rr1是左值!
1
2
注意: 變數是左值,因此我們不能將一個右值引用直接繫結到一個變數上,即使這個變數是右值引用型別也不可以。
3.標準庫move函式
雖然不能將一個右值引用直接繫結到一個左值上,但我們可以顯式地將一個左值轉換為對應的右值引用型別。我們可以通過呼叫一個名為move的新標準庫函式來獲得繫結到左值上的右值引用,此函式定義在標頭檔案utility中。
int &&rr3 =std::move(rr1); //OK
1
move呼叫告訴編譯器:我們有一個左值,但我們希望像右值一樣處理它。我們必須認識到,呼叫move就意味著承諾:除了對rr1賦值或者銷燬之外,我們將不再使用它。在呼叫move之後,我們不能對移後源物件的值做任何假設。
注意:
1.我們可以銷燬一個移後源物件,也可以賦予它新值,但是不能使用一個移後源物件的值。
2.對於move的使用應該是std:move而不是move。這樣做可以避免潛在的名