c++中的左值与右值
轉(zhuǎn)載自?http://www.cnblogs.com/catch/p/3500678.html
左值 (lvalue)和右值 (rvalue) 是 c/c++ 中一個比較晦澀基礎(chǔ)的概念,有的人可能甚至沒有聽過,但這個概念到了 c++11 后卻變得十分重要,它們是理解 move, forward 等新語義的基礎(chǔ)。
左值右值的定義
左值與右值這兩概念是從 c 中傳承而來的,在 c 中,左值指的是既能夠出現(xiàn)在等號左邊也能出現(xiàn)在等號右邊的變量(或表達(dá)式),右值指的則是只能出現(xiàn)在等號右邊的變量(或表達(dá)式).int a; int b;a = 3; b = 4; a = b; b = a;// 以下寫法不合法。 = a; a+b = 4;在 c 語言中,通常來說有名字的變量就是左值(如上面例子中的 a, b),而由運算操作(加減乘除,函數(shù)調(diào)用返回值等)所產(chǎn)生的中間結(jié)果(沒有名字)就是右值,如上的 3 + 4, a + b 等。我們暫且可以認(rèn)為:左值就是在程序中能夠?qū)ぶ档臇|西,右值就是沒法取到它的地址的東西(不完全準(zhǔn)確),但如上概念到了 c++ 中,就變得稍有不同。
具體來說,在 c++ 中,每一個表達(dá)式都會產(chǎn)生一個左值,或者右值,相應(yīng)的,該表達(dá)式也就被稱作“左值表達(dá)式", "右值表達(dá)式"。對于內(nèi)置的基本數(shù)據(jù)類型來說(primitive types),左值右值的概念和 c 沒有太多不同,不同的地方在于自定義的類型,而且這種不同比較容易讓人混淆:
1) 對于內(nèi)置的類型,右值是不可被修改的(non-modifiable),也不可被 const, volatile 所修飾(cv-qualitification ignored)
2) 對于自定義的類型(user-defined types),右值卻允許通過它的成員函數(shù)進(jìn)行修改。
對于 1),這和 C 是一致的,2) 卻是 C++ 中所獨有, 因此,如果你看到 C++ 中如下的寫法,千萬不要驚訝:
class cs {public:cs(int i): i_(i) { cout << "cs(" << i <<") constructor!" << endl; }~cs() { cout << "cs destructor,i(" << i_ << ")" << endl; }cs& operator=(const cs& other){i_ = other.i_;cout << "cs operator=()" << endl;return *this;}int get_i() const { return i_; }void change(int i) { i_ = i; }private:int i_; };cs get_cs() {static int i = 0;return cs(i++); }int main() {// 合法(get_cs() = cs(2)).change(323);get_cs() = cs(2);// operator=()get_cs().change(32);return 0; }這個特性看起來多少有些奇怪,因為通常來說,自定義類型應(yīng)該設(shè)計得和內(nèi)置類型盡量一樣(所謂 value type),但這個特性卻有意無意使得自定義類型特殊化了。對此,我們其實可以這樣想,也許會好理解點:自定義類型允許有成員函數(shù),而通過右值調(diào)用成員函數(shù)是被允許的,但成員函數(shù)有可能不是 const 類型,因此通過調(diào)用右值的成員函數(shù),也就可能會修改了該右值,done!
左值引用,右值引用
關(guān)于右值,在 c++11 以前有一個十分值得關(guān)注的語言的特性:右值能被 const 類型的引用所指向,所以如下代碼是合法的。
const cs& ref = get_cs();而且準(zhǔn)確地說,右值只能被 const 類型的 reference 所指向:
// error cs& ref = get_cs();
當(dāng)一個右值被 const reference 指向時,它的生命周期就被延長了,這個用法我在前面一篇博客里講到過它的相關(guān)應(yīng)用。其中暗藏的邏輯其實就是:右值不能當(dāng)成左值使用(但左值可以當(dāng)成右值使用).
另外值得注意的是,對于前面提到的右值的兩個特性:
1) 允許調(diào)用成員函數(shù)。
2) 只能被 const reference 指向。
它們導(dǎo)致了一些比較有意思的結(jié)果,比如:
void func(cs& c) {cout << "c:" << c.get_i() << endl; }//error func(get_cs());//正確 func(get_cs() = get_cs());其中: func(get_cs() = get_cs()); 能夠被正常編譯執(zhí)行的原因就在于,cs 的成員函數(shù) operator=() 返回的是 cs&!不允許非 const reference 引用 rvalue 并不是完美的,它事實上也引起了一些問題,比如說拷貝構(gòu)造函數(shù)的接口不一致了,這是什么意思呢?
class cs {public: cs& operator=(const cs& c); };// 另一種寫法 class cs2 {public: cs2& operator=(cs2& c); }; 上面兩種寫法的不同之處就在于參數(shù),一個是 const reference,一個是非 const。對于自定義類型的參數(shù),通常來說,如果函數(shù)不需要修改傳進(jìn)來的參數(shù),我們往往就按 const reference 的寫法,但對于 copy constructor 來說,它經(jīng)常是需要修改參數(shù)的值,比如 auto_ptr。
// 類似auto_ptr class auto_ptr {public:auto_ptr(auto_tr& p){ptr_ = p.ptr_;p.ptr_ = NULL;}private:void* ptr_; }; 所以,對于 auto_ptr 來說,它的 copy constructor 的參數(shù)類型是 non const reference。有些情況下,這種寫法應(yīng)該被鼓勵,畢竟 non const reference 比 const reference 更能靈活應(yīng)對各種情況,從而保持一致的接口類型,當(dāng)然也有代價,參數(shù)的語義表達(dá)不準(zhǔn)確了。除此更大的問題是如果拷貝構(gòu)造函數(shù)寫成這樣子,卻又對 rvalue 的使用帶來了極大的不變,如前面所講的例子,rvalue 不能被 non const reference 所引用,所以像 auto_ptr 的這樣的類的 copy constructor 就不能接受 rvalue.
// 錯誤 auto_ptr p(get_ptr());// operator=() 同理,錯誤。 auto_ptr p = get_ptr(); 這也是 auto_ptr 很不好用的原因之一,為了解決這個問題,c++11 中引入了一種新的引用類型,該種引用是專門用來指向 rvalue 的,有了這種新類型,對 lvalue 和 rvalue 的引用就能明確區(qū)分開來了。
總結(jié)
以上是生活随笔為你收集整理的c++中的左值与右值的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 011_Validation Rule
- 下一篇: jquery之仿京东菜单