左值引用和右值引用隨筆

左值引用VS右值引用

左值引用對於通常的C++程序員再熟悉不過,但對於右值引用(C++0X新特性),就稍微有點不知所云html

左值VS右值

在定義變量的時候,常常會用到左值和右值,好比:
int a = 1;
int b = a + 1;linux

上面這段代碼,a先做爲左值,在做爲右值。在做爲右值的時候,是至關於(原理上等同,但不必定對)ios

int tmp(a + 1);
int b(tmp);c++

中間會先創建一個臨時遍歷,而後在把臨時遍歷賦值給b。對於數,只能做爲左值,而變量名,便可以做爲左值又能夠做爲右值。(做爲左值的時候至關於用該變量的地址,做爲右值的時候則至關於使用該變量的內容,這裏對於類對象也成立)。程序員

左值引用

用法:Type & 左值引用名 = 左值表達式;api

注意點:聲明時必須初始化,初始化以後沒法在改變;對別名的一切操做都等價於對原來變量的操做。數組

左值引用在傳遞參數的時候,和指針特別相似,如如下代碼:函數

int val = 10;
void fun(int * ptr){ cout<<*ptr<<endl; *ptr += 1; }
void fun(int & value){ cout<<value<<endl; a += 1; }
fun(val);
fun(&val);.net

上面的兩種fun()的調用方法,在函數體內的修改均可以引發val的改變。(簡單的理解,不必定徹底正確:左值引用和指針都至關因而經過地址來訪問具體的值,所以能夠修改)指針

const修飾左值引用

int & r = val + 1; //此句不合法,由於右值沒法賦值給左值引用
const int& r = val + 1;//合法

解釋:資料說c++中臨時變量默認const屬性,因此只能傳給const的引用。規定右值不能綁定到非 const 限定的左值引用。
異常對象另說;若是是右值引用或const左值引用綁定的,那生存期延長爲引用;不然到徹底表達式結束銷燬。還有默認初始化數組元素時延長到數組初始化結束。(摘抄自其網頁)

右值引用

在上面的代碼中,咱們沒法創建 int &rb = a + 1; 這樣的語法,由於a + 1 此時是做爲一個右值來使用的,咱們沒法把一個右值賦值給一個左值引用。(也就是左值引用至關於把一個變量的地址付給另外一個變量,這兩個變量能夠訪問同一個內存,右值僅僅是一個數,而非內存中的某塊地址,所以沒法把右值複製給左值引用)。

聲明方法:Type && 右值引用名 = 右值表達式;

std::move()的用法

能夠直接把左值或者右值轉換成右值引用,使用方法:

int && rrval = std::move(val);

可是這裏須要注意:在調用完std::move以後,不能再使用val,只能使用 rrval,這一點用於基本類型可能沒什麼直接影響,當應用到類函數的時候,用好std::move 能夠減小構造函數數的次數,具體的使用參考下面的std::move比較好的理解
下面說一下本身的理解:
    首先是因爲STL裏面默認的庫已經支持右值引用,也有所謂的移動構造函數以下面的形式A (A&& a){} 這裏不能使用const A&& a,由於須要改變a。移動構造函數主要的用途是,當你不須要在使用一個變量的時候,能夠直接經過該構造函數來實現把該變量的數據轉換到另外一個變量中,省去調用默認的賦值構造或者拷貝構造函數帶來額外的開銷,如string類在賦值或者拷貝構造函數中會聲明char數組來存放數據,而後把原string中的 char 數組被析構函數釋放,若是a是一個臨時變量,則上面的拷貝,析構就是多餘的,徹底能夠把臨時變量a中的數據直接 「轉移」 到新的變量下面便可。 以下面的程序(摘抄自網頁):

#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{
    std::string str = "Hello";
    std::vector<std::string> v;
    //調用常規的拷貝構造函數,新建字符數組,拷貝數據
    v.push_back(str);
    std::cout << "After copy, str is \"" << str << "\"\n";
    //調用移動構造函數,掏空str,掏空後,最好不要使用str
    v.push_back(std::move(str));
    std::cout << "After move, str is \"" << str << "\"\n";
    std::cout << "The contents of the vector are \"" << v[0]
                                         << "\", \"" << v[1] << "\"\n";
}


總結:


其實這個右值引用主要的用處就是在於配合std::move來實現 「轉移語句」
A();//默認構造函數
A(const A& a);//拷貝構造函數
oprator=(const A& a);//賦值構造函數
A(A&& a);//移動構造函數
能夠在移動構造函數中實現 把a的數據直接轉移到 新的變量b下面,而省去 申請聲明一個變量b, 把 copy a->b, 而後釋放 a
的空間。
好比,string str = 「hello"; 如今str不在使用了,但須要聲明一個新的變量表示str, 此時就能夠用 string newstr(str::move(str)); 調用移動構造函數,把str下面的內容所有轉移到 newstr下面,「掏空」str,這裏須要注意掏空str以後,最好就不要在使用str了。(有點囉嗦了)


註釋:
     賦值構造函數:A & operator = (const A& a); //這裏返回A & 是爲了進行連等 a1 = a2 = a3,當一個變量已經被定義以後,改變值的時候調用該函數
     拷貝構造函數:A(const A&a); 直接在定義聲明一個對象的時候,依據另外一個對象來構造。

參考連接:

左值右值定義:http://www.cnblogs.com/catch/p/3500678.html
右值表達式VS左值表達式:http://blog.sina.com.cn/s/blog_7fe1e77b01016okx.html
左值引用和右值引用:http://www.linuxidc.com/Linux/2015-02/114056.htm
右值引用:http://blog.csdn.net/zwvista/article/details/12306283
臨時對象不能綁定到非const左值引用上:http://blog.csdn.net/liuxialong/article/details/6539717
http://blog.csdn.net/feeltouch/article/details/9789731

std::move用法理解
     std::move比較好的解釋http://www.cnblogs.com/chezxiaoqiang/archive/2012/10/24/2736630.html
另外三篇關於std::move 的用法:
上:http://blog.csdn.net/yapian8/article/details/42341307
中:http://blog.csdn.net/yapian8/article/details/42341321
下:http://blog.csdn.net/yapian8/article/details/42341351

相關文章
相關標籤/搜索