1. 程式人生 > >C++左值右值和移動語義

C++左值右值和移動語義

最近看了很多相關部落格,自己總結一下,單純根據在等號左邊還是右邊明顯判斷太過粗糙,我的大致理解如下:
判斷object是左值還是右值(三種方法):
(1)object能否被取地址,即&object是否合法;
(2)object能否被賦值,即object=other_object是否合法;
(3)object在當前語句執行完就銷燬還是會繼續存在,即臨時物件還是持久物件;
然後是左值引用和右值引用,其實兩者就是指引用,只是左值引用引用的是左值,右值引用引用的是右值。為了更進一步解釋,我們看看下面的例子:

int add(int a, int b)
{
    return
a + b; } cout << add(2, 3);

這是最簡單的版本,我們沒有使用任何引用,但是這會導致函式呼叫和返回過程中造成多次拷貝消耗,浪費計算資源,接下來看看左值引用:

int& add(int a, int b)
{
    return a + b;
}
cout << add(2, 3);

這裡期待的返回值是左值引用,但是函式內返回的是(a+b),根據開始的判斷方法,這是一個右值,沒法賦值給一個左值引用(vs2013提示“非常量引用的初始值必須為左值”),既然是強調非常量引用,而我又不想把(a+b)賦值給一個變數然後再返回該變數(太麻煩),那就修改為期待返回一個常量左值引用吧,修改如下:

const int & add(int a, int b)
{
    return a + b;
}
cout << add(2, 3);

那再改改呢?如下:

const int & add(int& a, int& b)
{
    return a + b;
}
cout << add(2, 3);

這樣函式定義是沒錯,但是呼叫卻會出現問題,因為期待的傳入引數是左值引用,而我卻傳入2和3這樣的右值,這裡有兩種方法:
(1)將形參改為常左值引用:

const int & add(const int
& a,const int& b) { return a + b; } cout << add(2, 3);

(2)將右值實參轉換為左值再傳進函式:

int x=2,y=3;
const int & add( int& a, int& b)
{
    return a + b;
}
cout << add(x, y);

接下來看看右值引用版本:

int && add(int a, int b)
{
    return a + b;
}
cout << add(x, y);

這是沒有問題的,但是如果改成下面的情況:

int && add(int a, int b)
{
    int sum= a + b;
    return sum;
}
cout << add(x, y);

VS2013提示無法將右值引用繫結到左值,那麼就把左值轉換為右值:

int && add(int a, int b)
{
    int sum= a + b;
    return std::move(sum);
}
cout << add(x, y);

到這裡,例子說的已經可以啦,總結一下就是:
(1)值傳遞時沒有太多考慮,就是效率低點,不會影響編譯正確性;
(2)右值引用只能繫結到右值;
(3)左值引用只能繫結到左值;
(4)常左值引用可以繫結到右值;
(5)右值賦給一個變數後即可表示為左值;
(6)使用std::move()可以將左值轉換為右值;
好的,使用以上知識 大致可以避免左右值引用產生的編譯錯誤了,這是我的理解。