C++中左值與右值

讓我們先看看一些常見的左值和右值舉例:

int var = 6;          // var is a lvalue

const int var = 6;    // var is a (nonmodifiable) lvalue

char str[] = "hello, world"; // str is a (nonmodifiable) lvalue

"hello, world";       // the expression is string literal,

                       //so it's a rvalue

string("hello, world"); // the expresion is a (modifiable) rvalue

     對於每一個表達式,其要麼是一個左值(lvalues),要麼是一個右值(rvalue)。
   左值這個概念最初來源於賦值語句:E1 = E2;,這裏要求左操作數E1是一個(可修改的)左值。現在,左值這個概念的含義已不侷限於此。而右值是相對於左值出現的非左即右
   雖然左值和右值的內涵和外延有了很大變化,但仍滿足這條規則:右值只能出現在賦值運算符的右邊,不能出現在它的左邊。
   一個左值對應於(refer to)一個對象或者函數(注:函數不是對象)[注1]

   右值的類型總是完整類型或者void類型。注意兩點:(1)void類型(非完整類型)是右值;(2)當右值的類型不是void類型時,其必須是完整類型,因爲需要計算它的值。由此可知,非void的非完整類型是左值

 

C++中的左值和右值

1.   概念
變量和文字常量都有存儲區,並且有相關的類型,區別在於變量是可尋址的;
對於每個變量,都有2個值與其相關聯:
1>數據值,存儲在某個內存地址中,也稱右值(rvalue),右值是被讀取的值(read value),文字常量和變量都可被用於右值。
2>地址值,即存儲數據值的那塊內存地址,也稱左值(lvalue),文字常量不能被用作左值。
2 . 問題
給表達式加上括號: ++a--
結果 ++(a--)
這個表達式是非法的,因爲前增量操作要求一個可修改的左值,而 "a--" 不是左值(即右值)
3 . 前增量和後增量的區別
早期的c語言教材,for循環語句通常寫成:
for(int i=0;i<10;i++)
而現在多爲:
for(int i=0;i<10;++i)
兩者有區別嗎?
a++ 即是返回 a的值,然後變量 a 加 1,返回需要產生一個臨時變量類似於
{
       int temp = a;
       a=a+1;
       return temp; //返回右值
}
++a 則爲:
{
    a=a+1;
    return &a;    //返回左值
}
顯然,前增量不需要中間變量,效率更高。

 

注1:對象類型爲非函數、非引用、非void的類型;左值所對應的對象不一定實際存在。例如:char* p; *p這個左值所對應的對象目前是不存在的。

   部分右值表達式也可以對應對象。例如,那些調用構造函數和調用那些返回類對象的函數的表達式,這些表達式可以調用相應對象的成員函數,但這些表達式是右值(此時,該右值可能是可修改的右值)。

   如果在左值被計算時還沒有指定一個對象,那麼該計算行爲是未定義的。例如:char* p;此時計算*p的結果是未知的。
   函數調用是左值,當且僅當返回類型是引用。[注2]
   在任何時候,當一個左值出現在需要右值的地方,左值會被轉換成右值[注3]       

注3:當左值類型T爲非函數、非數組類型時,左值可以被轉換爲右值。如果T是非void的非完整類型,那麼此時左值不應該被轉化爲右值來使用;如果該左值所對應的對象不是類型T的對象,也不是由T派生的類型的對象,或者該對象沒有被初始化,那麼發生這種轉換的程序將產生未定義行爲。

   如果T是非類類型,那麼轉換得到的右值的類型是T的CV-qualified版本;否則,右值類型是T。

   左值所對應的對象所包含的值就是右值的結果。 在發生這種轉換時,左值的值並不是一定被計算。例如:當運算符sizeof的操作數發生這種轉換時,並不需要訪問左值的值,因爲該運算符不需要計算它的操作數。

   左值分爲可修改的左值(modifiable)和不可修改的左值(nonmodifiable)。

   如果要修改一個對象,該對象必須是左值;例外情況是,類類型的右值也可以在某些情形下修改它所對應的對象。例如,函數調用返回的類是右值,但可以調用其成員函數修改該對象。

   由const限定的表達式不可以被修改;除非這是一個類類型,並且擁有mutable成員,那麼該mutable成員可以被修改。

   非類類型的右值總是由CV-qualifiers限定,類類型的右值可以沒有CV-qualifiers。

   部分內置運算符需要左值操作數。例如,所有內置賦值運算符要求它們的左操作數是一個左值(此時還是一個可修改的左值)。

  部分內置運算符需要右值操作數,並且產生右值。例如,一元運算符和二元運算符“+”要求操作數爲右值,並且它們產生的結果也爲右值。

   部分內置運算符和函數調用產生左值。例如,如果E是一個指針類型的表達式,那麼*E是一個左值表達式(注:*運算符的操作數是左值,產生一個左值)。又如,函數 int& f();產生一個左值,因此f()的調用是一個左值表達式。

    如果一個程序試圖通過一個左值的非下列類型去訪問存儲在對象中的值,那麼該行爲是未定義的。

注2:自定義運算符是函數,這類運算符是否需要或者產生左值取決於它們的參數和返回值類型。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章