左值(lvalue),右值(rvalue) 是 c/c++ 中乙個比較晦澀的概念,有的人可能甚至沒有聽過,但這個概念到了 c++11 後卻變得十分重要,它們是理解move(),forward()等新語義的基礎。
左值與右值這兩概念是從c中傳承而來的,在c中,左值指的是能夠出現在等號左邊及右邊的變數(表示式),右值則指的是只能出現在等號右邊的變數(表示式).
int在 c 語言中,通常來說有名字的變數就是左值(如上面例子中的a, b),而由運算操作(加減乘除,函式呼叫返回值等)產生的中間結果(沒有名字)就是右值,如上的3+4, a + b等。a;int
b;a = 3
;b = 4
;a =b;
b =a;
//不合法。
3 =a;
a+b = 4;
我們暫且可以認為:左值就是在程式中能夠尋值的東西,右值就是沒法取到它的位址的東西(不完全準確),但
如上概念到了c++中,就變得稍有不同。
在c++中,每乙個表示式都會產生乙個左值,或者右值,相應的,該表示式也就被稱作「左值表示式」,「右值表示式」。對於內建的基本資料型別來說(build-in types),左值右值的概念和 c 沒有太多不同,不同的地方在於自定義的型別。
而且這種不同比較容易讓人混淆:
1) 對於內建的型別,右值是不可被修改的(non-modifiable),也不可被const, volatile 所修飾(cv-qualitification ignored)
2) 對於自定義的型別(user-defined types), 右值卻允許通過它的成員函式進行修改。
對於1),這和c是一致的,2) 卻是c++中所獨有, 因此,如果你看到c++中如下的寫法,千萬不要驚訝:
class這個特性多少有些奇怪,通常來說,c++ 中的自定義型別是應該設計地盡量和內建型別一樣才對的,但這個特性卻偏偏違背了這個原則。cs ~cs()
cs& operator=(const cs&other)
int get_i() const
void change(int i)
private
:
inti_;
};cs get_cs()
intmain()
對於這個特性,我們其實可以這樣想,也許會好理解點:自定義型別允許有成員函式,而通過右值呼叫成員函式是被允許的,但成員函式有可能不是 const 型別,因此通過呼叫右值的成員函式,也就可能會修改了該右值,done!
關於右值,有乙個十分值得關注的語言的特性:右值能被 const 型別的引用所指向
const cs& ref = get_cs();而且只能被const 型別的 reference 所指向:
//當乙個右值被 const reference 指向時,它的生命週期就被延長了,這個用法我在前面一篇部落格裡講到過它的相關應用,點這。error
cs& ref = get_cs();
這裡暗藏邏輯其實就是:右值不能直接轉化成左值(但左值可以轉化為右值).
關於前面提到的右值的兩個特性:
1) 允許呼叫成員函式。
2) 只能被const reference指向。
導致了一些比較有意思的結果,比如:
void func(cs&c)其中:func(get_cs() = get_cs()); 能夠被正常編譯執行的原因就在於,cs 的成員函式 operator=() 返回的是 cs&!//error
func(get_cs());
//正確
func(get_cs() = get_cs());
不允許非 const reference 引用 rvalue 並不是完美的,它事實上也引起了一些問題,比如說拷貝建構函式的介面不一致了,這是什麼意思呢?
classcs;上面兩種寫法的不同之處就在於引數,乙個是const reference,乙個是非const.//另一種寫法
class
cs2;
通常來說,如果不需要修改傳進來的引數,我們往往就按 const reference 的寫法,但對於copy constructor 來說,它經常是需要修改引數的值,比如 auto_ptr。
//所以,對於auto_ptr來說,它的 copy constructor 的引數型別是 non const reference。類似auto_ptr
class
auto_ptr
private
:
void*ptr_;
};
這個種寫法本來應該被鼓勵的,non const reference 比 const reference 更能靈活應對各種情況,從而保持一致的介面型別。
但如果拷貝建構函式寫成這樣子,卻又對 rvalue 的使用帶來了極大的不變,如前面所講的例子,rvalue 不能被 non const reference 所引用,所以像auto_ptr的這樣的 copy constructor 就不能接受 rvalue.
//這也是auto_ptr很不好用的其中乙個原因。錯誤auto_ptr p(get_ptr());
//operator=() 同理,錯誤。
auto_ptr p = get_ptr();
為了解決這個問題,c++11 中引入了一種新的引用型別,該種引用是專門用來指向 rvalue 的,有了這種新型別,對 lvalue 和 rvalue 的引用就能明確區分開來了,而在之前,它們是一樣的。
因為有了這種新的型別,接著就引出了c++11 中新的語義,move(), forward() 等,這兒先賣個關子,我們下次再講。
C 中的左值和右值
1.概念變數和文字常量都有儲存區,並且有相關的型別,區別在於變數是可定址的 對於每個變數,都有2個值與其相關聯 1 資料值,儲存在某個記憶體位址中,也稱右值 rvalue 右值是被讀取的值 read value 文字常量和變數都可被用於右值。2 位址值,即儲存資料值的那塊記憶體位址,也稱左值 lva...
C 中的左值和右值
左值 lvalue 應該被解釋被location value,即可被定址的值 右值 rvalue 應該被解釋為read value,即唯讀的值,而不能被定址 這樣理解應該更為準確一點 通俗的講,左值就是能夠出現在賦值符號左面的東西,而右值就是那些可以出現在賦值符號右面的東西了。舉個很簡單的例子 a ...
C 中的左值和右值
在c 中,可以放到賦值操作符 左邊的是左值,可以放到賦值操作符右邊的是右值。有些變數既可以當左值又可以當右值。進一步來講,左值為lvalue,其實l代表location,表示在記憶體中可以定址,可以給它賦值 常量const型別也可以定址,但是不能賦值 rvalue中的r代表read,就是可以知道它的...