C 11 中 的Move語義 和 右值引用

2021-06-21 05:02:13 字數 2941 閱讀 1329

c++是用來產生更快的**,但是c++中的臨時物件降低了c++的效能。某些臨時物件可以被編譯器優化(比如,函式返回值優化),但是有時候臨時物件會造成嚴重的物件拷貝(比如deep copy)。

舉例如下:

#include using namespace std;

vectordoublevalues (const vector& v)

return new_values;}

int main()

v = doublevalues( v );

}

其中,v = doublevalues(v),發生了兩次拷貝。第一次在doublevalues()中,函式返回值是乙個臨時物件,需要將new_values拷貝到這個臨時物件中(呼叫copy constructor),這次拷貝可能會被編譯器自動優化。第二次拷貝是將臨時物件的值賦給v(呼叫了assignment function),這需要重新分配空間並且遍歷整個vector進行賦值。

雖然我們有其他的辦法來避免這種情況,比如通過返回指標或者傳遞引用的方式。但是這些方式都不是自然。這段**最壞的地方是從 doublevalues()返回的物件是乙個臨時物件,而這個臨時物件是很快就不再需要了。一旦把臨時物件的值 copy 到 v 中,這個臨時物件就不再需要了。但是直觀來看,最簡單的辦法是通過將臨時物件中的指標儲存到 v 中,而跳過整個copy過程。這就是所謂的 move**移)。但是在c++03中這個功能並不能實現,因為你無法通過賦值函式,或者copy ctor判斷傳遞其的物件是否是臨時物件(temporary object),從而也就無法實現move功能了。但是在c++11中,你可以做到!

這就是move語義和右值引用的目的。move 語義允許你通過將乙個臨時物件中的資源安全的轉移到另外乙個物件中,避免了資源浪費。

move 語義依賴c++11中的新特性:右值引用。我們首先了解什麼是右值,然後在了解什麼是右值引用,最後我們來理解這到底是如何工作的。

rvalues and lvalues (右值和左值)

簡單來說,左值是可以出現在賦值號左邊的表示式,右值是出現在賦值號右邊的表示式。左值有分配空間,我們可以給其賦值。

左值不一定是變數。

int x;          // 全域性變數

int& getref ()

getref() = 4; // 返回全域性變數的引用。 getref()也是左值。

右值-----如果乙個表示式返回乙個臨時物件,那麼這個表示式是右值。例如:

int x;         // x 是全域性變數

int getval ()

getval(); // 返回臨時變數,所以這裡getval()是右值。

當函式返回值型別是物件而不是int型別時:

string getname ()

getname(); //返回乙個string 型別的臨時變數,也是右值。

string str = getname();

最關鍵的事情是要記住 「右值指的是臨時物件」!!!

通過"右值引用" 來 引用臨時物件

在c++03中,可以採用如下方式引用乙個臨時物件,但是這個引用必須是const。

const string& name = getname(); // ok

string& name = getname(); // not ok

這裡,只能通過const 引用乙個臨時物件,所以你不能對乙個臨時物件進行操作。

在c++11中,允許你使用「rvalue reference」來引用乙個臨時物件,並且這個引用可以是非const的。

const string&& name = getname(); // ok

string&& name = getname(); // also ok - praise be!

要清楚幾點:

1) rvalue reference 只能引用臨時物件。

2) rvalue reference 可以是const 也可以是非const。只是非const很少使用

3) rvalue reference 使用&& 語法表示引用臨時物件。

右值引用最重要的作用是,當右值引用和左值引用分別作為函式的引數時,進行函式過載,會發生尤其有意思的事情。

printreference (const string& str)    //#1

printreference (string&& str) //#2

#1的引數是乙個左值引用,它會接受所有的引數,不管這個引數是左值還是右值,無論這個引數是可變的還是不可變的。

#2的引數是乙個右值引用,它指接受可變的右值(也就是可變的臨時物件)。

舉例如下:

string me( "alex" );

printreference( me ); // 呼叫 #1

printreference( getname() ); // 呼叫#2 作為可變的右值引用

好了,現在我們有方法(右值引用)來判斷乙個物件是臨時物件還是permanent object(永久物件,相對於臨時物件)。 

那我們如何通過這個方法來使用臨時物件呢? 或者說我們如何利用這個方法呢?(目的是避免深度copy,提公升程式效率)

move constructor and move assignment operator

(未完待續。。。)

C 11 右值引用與move語義

1.右值引用 1.1 右值 右值就是指在下乙個分號後 更準確的說是在包含右值的完整表示式的最後 銷毀的臨時物件。對於c 11,編譯器會依據引數是左值還是右值在複製建構函式和move建構函式間進行選擇。怎樣區分呢?the distinguishing criterion is if it has a ...

C 11右值 右值引用以及move語義

1 字面常量 1 3,2 等 2 臨時物件 返回非引用型別的函式,算術 關係 位以及後置遞增 遞減原算符 注意 左值引用的函式,賦值 下標 解引用和前置遞增 遞減運算子返回都為左值 3 無名物件 4 一般函式的返回值也為右值 class myclass myclass 右值 1 右值引用只能繫結到臨...

C 11中的右值引用及move語義程式設計

c 0x中加入了右值引用,和move函式。右值引用出現之前我們只能用const引用來關聯臨時物件 右值 造孽的vs可以用非const引用關聯臨時物件,請忽略vs 所以我們不能修臨時物件的內容,右值引用的出現就讓我們可以取得臨時物件的控制權,終於可以修改臨時物件了!而且書上說配合move函式,可以大大...