標籤:基礎資料型別 (Elementary Data Type) 基本 類型 地址 creat reference free 不能 value
c/c++ 右值引用轉自:https://www.cnblogs.com/catch/p/3500678.html
左值(lvalue)和右值(rvalue)是 c/c++ 中一個比較晦澀基礎的概念,不少寫了很久c/c++的人甚至沒有聽過這個名字,但這個概念到了 c++11 後卻變得十分重要,它們是理解 move/forward 等新語義的基礎。
左值右值的定義
左值與右值這兩概念是從 c 中傳承而來的,在 c 中,左值指的是既能夠出現在等號左邊也能出現在等號右邊的變數(或運算式),右值指的則是只能出現在等號右邊的變數(或運算式).
int a;int b;a = 3;b = 4;a = b;b = a;// 以下寫法不合法。= a;a+b = 4;
在 c 語言中,通常來說有名字的變數就是左值(如上面例子中的 a, b),而由運算操作(加減乘除,函數調用傳回值等)所產生的中間結果(沒有名字)就是右值,如上的 3 + 4, a + b 等。我們暫且可以認為:左值就是在程式中能夠尋值的東西,右值就是沒法取到它的地址的東西(不完全準確),但如上概念到了 c++ 中,就變得稍有不同。具體來說,在 c++ 中,每一個運算式都會產生一個左值,或者右值,相應的,該運算式也就被稱作“左值運算式", "右值運算式"。對於基礎資料型別 (Elementary Data Type)來說(primitive types),左值右值的概念和 c 沒有太多不同,不同的地方在於自訂的類型,而且這種不同比較容易讓人混淆:
1) 對於基礎類型,右值是不可被修改的(non-modifiable),也不可被 const, volatile 所修飾(cv-qualitification ignored)
2) 對於自訂的類型(user-defined types),右值卻允許通過它的成員函數進行修改。
對於 1),這和 c 是一致的,2) 卻是 C++ 中所專屬, 因此,如果你看到 C++ 中如下的寫法,千萬不要驚訝:
#include <iostream>using namespace std;class Test{public: Test(int d) : data(d){cout << "create:" << data << endl;} ~Test(){cout << "free:" << data << endl;} Test& operator = (const Test& other){ //data = other.data; cout << "operator" << endl; return *this; } int get_data() const {return data;} void set_data(int d){data = d;}private: int data;};Test getTest(){ int static i = 0; return Test(i++);}void func(Test& t){ cout << "func:" << t.get_data() << endl;}int main(){ //1 合法 (getTest() = Test(1)).set_data(12); getTest() = Test(2); getTest().set_data(20); //2 只能用const引用接收右值引用 const Test& ref = getTest(); //Test& ref1 = getTest();//error //3 //func(getTest()); func(getTest() = getTest());}
這個特性看起來多少有些奇怪,因為通常來說,自訂類型應該設計得和內建類型盡量一樣(所謂 value type,value semantic),但允許成員函數改變右值這個特性卻有意無意使得自訂類型特殊化了。對此,我們其實### 可以這樣想,也許會好理解點:
<font color="red"自訂類型允許有成員函數,而通過右值調用成員函數是被允許的,但成員函數有可能不是 const 類型,因此通過調用右值的成員函數,也就可能會修改了該右值,done!
左值引用,右值引用
關於右值,在 c++11 以前有一個十分值得關注的語言的特性:右值能被 const 類型的引用所指向,所以如下代碼是合法的。
const Test& ref = getTest();
而且準確地說,右值只能被 const 類型的 reference 所指向,非 const 的引用則是非法的:
Test& ref1 = getTest();//error
當一個右值被 const 引用指向時,它的生命週期就被延長了。其中暗藏的邏輯其實就是:右值不能當成左值使用(但左值可以當成右值使用)。另外值得注意的是,對於前面提到的右值的兩個特性:
1) 允許調用成員函數。
2) 只能被 const reference 指向。
它們導致了一些比較有意思的結果,比如:
void func(Test& c){ cout << "c:" << c.get_data() << endl;}//errorfunc(getTest());//正確func(getTest() = getTest());
其中: func(get_cs() = get_cs()); 能夠被正常編譯執行的原因就在於,cs 的成員函數 operator=() 返回的是 cs&!
不允許非 const reference 引用 rvalue 並不是完美的。
c/c++ 右值引用