C 11新特性 移動語義和右值引用

2021-07-15 13:56:22 字數 2240 閱讀 9063

傳統的c++引用(左值引用)使得識別符號關聯到左值。左值是乙個表示資料的表示式(如變數名或解除引用的指標),程式可以獲得其位址。

c++11新增了右值引用。右值引用,顧名思義,可以關聯到右值,即——可以出現在賦值表示式的右邊,但不能對其應用位址運算子的值。

右值包括字面常量(c風格字串除外,它表示位址)。諸如x+y等表示式以及返回值的函式(條件是該函式返回的不是引用)。

右值引用用符號&&表示。如:

int x = 10, y = 23;

int & r = x + y;//非法,編譯器報錯

int && r2 = x + y;//合法

double && r3 = std::sqrt(2.0);

將右值關聯到右值引用導致該右值被儲存到特定的位置,且可以獲取該位置的位址。也就是說,雖然不能將運算子&用於12或者(x + y),但可以將其用於r1。通過將資料與特定的位址關聯,使得可以通過右值引用來訪問該資料。

但其實這不是c++11引入右值引用的主要原因。

有些函式,表示式的執行會建立出臨時物件,在臨時物件即將被銷毀的時候,將字元,類物件等變數留在原來的地方,不去刪除它們,而是改變它們的所有權,使得它們仍然儲存在原來的位址上,但擺脫了臨時物件的身份,這種方法被稱為移動語義。

例如有乙個函式返回乙個臨時變數,此時編譯器做的工作就是,建立乙個該臨時物件的副本,然後將臨時物件銷毀,再將該臨時物件的副本賦值給乙個普通物件,然後銷毀該副本。而移動語義的做法是:直接將臨時物件的所有權交給該普通物件。

其實移動語義實際上避免了移動原始資料,而只是修改了記錄而已。

要實現移動語義,需要採取某種方式,讓編譯器知道什麼時候需要複製,什麼時候不需要。這就是右值引用發揮作用的地方。

對於類來說,可以定義乙個移動建構函式。與常規的複製建構函式(使用左值引用,而且一般宣告為const)不同,移動建構函式使用右值引用作為引數,該引用關聯到右值實參。而且不同與複製建構函式可執行的深複製,移動建構函式只是調整記錄。在將所有權轉移轉移給新物件的過程中,移動建構函式可能修改其實參,這意味著右值引用引數不應是const。

下面舉例說明移動建構函式的用法及其與複製建構函式的區別:

//為了偷懶,程式只列出了兩個建構函式的具體定義並說明他們的區別

#include "iostream"

using

namespace

std;

class example

//move constructor

example(example && f) : n(f.n)

~example();

};

下面語句使用的是複製建構函式,它執行深複製:

example two = one; //引用f指向左值物件one
下面語句使用的是移動建構函式:

example three (one + two);
在移動建構函式的定義中,它讓pc指向現有的資料,以獲取這些資料的所有權。此時,因為如果pc和f.pc指向相同的詩句,呼叫析構函式時將帶來麻煩,因為程式不能對同乙個位址呼叫兩次delete 。所以該建構函式隨後將原來的指標設定為空指標。這也是不宣告為const的原因。

這種奪取所有權的方式成為竊取。

簡而言之,實現移動語義的兩個步驟:使用右值引用告訴編譯器什麼時候可使用移動語義和編寫移動建構函式以提供所需的行為。

所以,通過提供乙個使用左值引用的複製建構函式和乙個使用右值引用的建構函式,兩個建構函式將初始化分成了兩組。

使用左值物件初始化物件時,將使用複製建構函式,而使用右值物件初始化物件時,將使用移動建構函式。

程式設計師可根據需要賦予這些建構函式不同的行為。

當然,適用於建構函式的移動語義考慮也適用於賦值運算子。如

example & example::operator=(example && f)
移動賦值運算子刪除目標物件中的原始資料,並將源物件的所有權轉讓給目標。

強制移動:

假設one two是兩個類物件,下面的語句將呼叫賦值運算子:

one =two;
但是如果不想呼叫複製運算子而是想直接使用移動語義呢?

c++11提供了標頭檔案utility中的move函式來進行轉換:

#include

one = std::move(two);

請注意:能這樣做的前提是已經定義了移動賦值運算子。

移動語義和右值引用(C 11)

左值 可以取位址 有名字的 右值 不能取位址 沒名字的 傳統的c 引用稱為左值引用,使得標誌符關聯到左值。c 11新增了右值引用,使用 表示。引入右值引用的主要目的之一是實現移動語義。在複製物件時,實現物件的移動而非拷貝。通過移動建構函式 移動賦值運算子實現 函式的引數為右值引用,函式內部並非深度複...

C 11 右值引用和移動語義

因為工作室要求寫技術部落格記錄學習到的知識點,自己之前是沒有寫過部落格的,所以現在用一篇介紹右值引用和移動語義的部落格作為部落格的第一篇,可能對於移動語義的理解還不夠深刻,但可以作為乙個簡單的介紹部落格 要理解好右值引用首先要知道什麼是左值?什麼是右值?1.左值是表示式結束後依然存在的持久化物件 2...

C 11的新特性 右值引用

先看 include pch.h include include using namespace std template class myarray void pushback t data private int mcapacity int msize elemtype paddr templa...