lvalue 引用 && rvalue 引用

C++中的每一個表達式要麼是lvalue要麼是rvalue。lvalue表示一個內存位置,而rvalue表示計算表達式的結果。數組

rvalue引用是對有名稱變量的引用,並容許變量表示的內存經過lvalue引用來訪問。ide

rvalue引用是對包含表達式結果的內存位置的引用。函數

總之,表達式的結果和函數內定義的變量都屬於臨時變量,即rvalue。spa

  int && num {2*x+3};   //rvalue引用表達式的臨時結果指針

  int & num {x=5};    //lvalue引用code

常量引用:blog

void GetSet(int &num)
{
 num += 1;
}

 Error (active)  initial value of reference to non-const must be an lvalue.內存

void GetSet(const int &num)
{
 num += 1;
}

上面代碼:只看第一個函數頭GetSet(變量)是正確的,但GetSet(常量5)會被報錯,由於編譯器不容許對常量存在可能潛在的更改行爲。ci

     規定常量做爲參數傳遞時需加const,即意味着不可更改。get

lvalue引用:

使用lvalue引用形參,能夠編寫直接訪問調用者實參的函數,避免了按值傳遞中的隱式複製。若不打算修改實參,則只須要給lvalue引用類型使用const修飾符,以免意外修改參數。

其實,不管是按值傳遞、按址傳遞參數或引用都是編譯器的規則,咱們須要熟悉參數在不一樣狀況下的傳遞,好的理解方式就是輸出地址來觀察。

void GetSet(int & num)
{
     num += 1;
}
int main()
{
     int v = 6;
     GetSet(v);
     cout << v<< endl;
     cin.get();
}

輸出結果: 7 ,num變量值經過引用改變了,能夠類比,變量的指針傳址方式。

rvalue引用:

void GetSet(int && num)
{
     num += 1;
}
int main()
{
     int v = 6;
     GetSet(v);
     cout << v<< endl;
     cin.get();
}

編譯器報錯:Error (active)  an rvalue reference cannot be bound to an lvalue 

可知lvalue不能經過rvalue引用,有rvalue引用形參的函數只能經過rvalue實參來調用。

void GetSet(int && num)
{
    num += 1;
    cout <<"num="<< num << endl;
}
int main()
{
    int v = 6;
    int c = 3;
    GetSet(v+c);
    cout <<"v="<< v <<" c="<< c <<endl;
    GetSet(5);
    cin.get();
}

上面代碼編譯經過,結果以下:

編譯器會爲表達式的結果生成一個臨時地址來存儲數值。而常量字面值 5 ,被當成一個表達式處理,而且存儲在函數引用形參的臨時位置。

輸出地址能夠看出,常量在rvalue引用的時候和表達式同樣處理了,即看作臨時變量。

函數返回值的引用:

int* GetSet(int num)
{
    num += 1;
    int result {num};
    return & result;
}
int main()
{
    int v = 6;
    int *ptr=GetSet(v);
    cout <<"ptr="<< *ptr << endl;
}

本段代碼能夠運行,但編譯器卻給出了以下警告:
「Warning C4172 returning address of local variable or temporary」

緣由在於:從函數中返回的引用是臨時變量的地址,應注意不要從函數中返回局部自動變量的地址。

能夠使用動態內存分配爲函數中的變量申請內存,因爲動態內存分配的內存是一直存在的(在堆中),除非用 delete 銷燬。即以下方式:

int* GetSet(int num)
{
    num += 1;
    int *result{ new int {num} };
    return result;
}
int main()
{
    int v = 6;
    int *ptr=GetSet(v);
    cout <<"ptr="<< *ptr << endl;
   delete ptr; }

 觀察下面兩部分代碼的不一樣:

1、
double
& lowest(double a[], int len) { int j{}; for (int i{ 1 }; i<len; i++) if (a[j]>a[i]) j = i; return a[j]; }
2、
double
& lowest(double a[], int len) { int j{}; for (int i{ 1 }; i<len; i++) if (a[j]>a[i]) j = i; return & a[j]; }

引用是賦予存在變量的別名,因此實際返回的是數組元素a[j]的引用,而不是改元素包含的值。a[j]的地址用來初始化要返回的引用,該引用是編譯器建立的,由於返回類型是引用。

但返回a[j]和返回&a[j]是不一樣的。

返回&a[j],則指定的是a[j]地址,那是一個指針。因此,第二部分代碼會被報錯以下:
  Error C2440 'return': cannot convert from 'double *' to 'double &' 

由於指針和引用屬於不一樣類型。

Const 在傳參引用中的潛規則的:

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

    long edge = 5L;
    double side = 3.0;
    double c1 = refcube(edge);
    double c2 = refcube(7.0);
    double c3= refcube(side+10.0);

上面代碼中的函數調用都會產生臨時變量:

  edge雖然是臨時變量,類型不正確,double引用不能指向long。

  參數7.0和side+10.0類型雖然正確,但沒有名稱,編譯器將生成一個函數期間調用的匿名臨時變量。

而如今若是咱們去掉 const ,會發現編譯器會報錯:

Error:a reference of type "double &" (not const-qualified) cannot be initialized with a value of type "long"

Error:initial value of reference to non-const must be an lvalue 

Why?

double refcube(double &ra) 是lvalue引用,要求使用知足類型的左值做爲參數。

那麼爲什麼 double refcube(double ra) 會經過編譯。

  由於直接調用和使用const同樣編譯器會產生 臨時變量,只不過使用了 const 意味着不能修改參數。

  1. 使用const能夠避免無心中修改數據。
  2. 可以處理const和非const實參,不然只能接受非const數據。
  3. 使用const引用使函數可以正確生成和使用臨時變量。

固然此處代碼是能夠使用rvalue引用或const rvalue引用,但 Long 類型沒經過報錯以下:

Error:'double refcube(const double &&)': cannot convert argument 1 from 'long' to 'const double &&'     

相關文章
相關標籤/搜索