C++中讓人忽視的左值和右值


前言

為了了解C++11的新特性右值引用,不得不重新認識一下左右值。學習之初,最快的理解,莫過於望文生義了,右值那就是賦值號右邊的值,左值就是賦值號左邊的值。在中學的數學的學習中,我們理解的是,左值等價於等號左邊的值,右值等價於等號右邊的值;當我們繼續學習C語言時,等號=不再叫等號,蓋頭換面叫做賦值號;那么來到C++我們還能這么理解嗎?答案是部分否定的。

假如你現在還是這樣理解,那么請繼續往下......

 

C++中何為左值lvalue和右值rvalue?

左值lvalue:可被引用的數據對象,例如,變量、數組元素、結構成員、引用和解除引用的指針都是左值。在C語言中,左值最初指的是出現在賦值語句左邊的實體,但這是引入const之前的情況。now,常規變量和const變量都可視為左值,因為可通過地址訪問它們。常規變量屬於可修改的左值,const變量屬於不可修改的左值。左值基本上和以前的認知沒有太大的改變。


右值rvalue:字面常量(用括號括起來的字符串除外,因為它們表示地址)、包含多項的表達式以及返回值的函數(條件是該函數返回的不是引用)。

 

簡單的區別左值和右值:
右值就是一個臨時變量(后面將詳細的解釋),只有臨時地址空間,左值有其地址空間,換句話說,使用取地址符&對某個值取地址,如果不能得到地址,則是右值!

例如:

int a = 0;

cout << &a << endl; // ok! lvalue

cout << &404;  // error! rvalue

 

對於前面提到的右值的特性

1) 允許調用成員函數。

2) 只能被 const reference 指向。

3) 右值不能當成左值使用,但左值可以當成右值使用

 

臨時變量

僅當函數參數為const reference時,臨時變量才能與之匹配。

 

什么時候將創建臨時變量呢?
如果引用參數是const,則編譯器將在下面兩種情況下生成臨時變量:
1. 實參的類型正確,但不是左值
2. 實參的類型不正確,但可以轉換為正確的類型

 

Example:

double cube(const double &ra)
{    
    return ra * ra * ra;
}

double side = 3.0;
double* pd = &side;
double& rd = side;
long edge = 5L;
double lens[5] = {2.0, 5.0, 10.0, 12.0};

double c1 = cube(side);
double c2 = cube(lens[2]);
double c3 = cube(rd);
double c4 = cube(*pd);

double c5 = cube(edge); // ra是臨時變量
double c6 = cube(7.0);    // ra是臨時變量
double c7 = cube(side + 4.0);    // ra是臨時變量

參數side、lens[2]、rd和*pd都是有名稱的、double類型的數據對象,因此不需要借助臨時變量,可以為其創建引用。
然而edge雖然有名稱但是類型卻不正確,正好符合產生臨時變量的情況2 “實參的類型不正確,但可以轉換為正確的類型” ,double引用不能指向long。參數7.0和side + 4.0的類型都正確,但是木有名稱,屬於右值。在這些情況下,編譯器都會生成一個臨時匿名變量,並讓ra指向它。這些變量生命周期只在函數調用期間,此后編譯器便會隨意的刪除。

 

為何臨時變量 or 右值 對const引用的限制時合理的呢?

請看下面的例子:

void swapr(int& a, int& b)    // swapr()完成數的交換的功能
{
    int temp;
    
    temp = a;
    a = b;
    b = temp;
}

long a = 5, b = 6;
swapr(a, b);

這里我們使用反證法,假設這個調用是木有錯誤的,那么這里的類型不匹配,因此編譯器將創建兩個int臨時變量,將它們初始化為3和5,然后交換臨時變量的內容,但是這只是交換了兩個臨時變量的值,a和 b並沒有交換這與swapr()函數完成的功能是相悖的。


總結來說,如果接受引用參數的函數的意圖是修改作為參數傳遞的變量,則創建臨時變量將阻止這種意圖的實現。解決方法是,禁止創建臨時變量。因此這個調用也是錯誤的。如果函數調用的參數是右值或與相應的const引用參數的類型不匹配,則C++將創建類型正確的匿名變量,將函數調用的參數的值傳遞給該匿名變量,並讓參數來引用該變量

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM