C 右值和移動

2021-10-01 16:02:17 字數 1850 閱讀 2083

自c++11以來,c++進入modern c++時代。移動語義是c++11裡引入的乙個重要概念;理解這個概念,是理解很多現代c++裡的優化的基準

我們常常會說,c++裡有左值和右值。這話不完全對。標準裡的定義實際更複雜,規定了下面這些值類別(value categories):

我們先理解一下這些名詞的字面含義:

值得注意的是:

函式名屬於不可修改的左值。

cout << ''返回的確實std::ostream型別的左值,但由於在basic_ostream類中,operator=被宣告為delete,故也不能進行賦值操作。

basic_ostream&

operator=(

const basic_ostream&)=

delete

;

"hello world"確實是const char[12]型別的左值,但是由於是const型別,它並不是可修改的左值,不能對其進行賦值。

在函式呼叫時,左值可以繫結到左值引用的引數,如t&。乙個常量只能繫結到常左值引用,如const t&。

在 c++11 之前,右值可以繫結到常左值引用(const lvalue reference)的引數,如 const t&,但不可以繫結到非常左值引用(non-const lvalue reference),如 t&。從 c++11 開始,c++ 語言裡多了一種引用型別——右值引用。右值引用的形式是 t&&,比左值引用多乙個 & 符號。跟左值引用一樣,我們可以使用 const 和 volatile 來進行修飾,但最常見的情況是,我們不會用 const 和 volatile 來修飾右值。本專欄就屬於這種情況。

引入一種額外的引用型別當然增加了語言的複雜性,但也帶來了很多優化的可能性。由於 c++ 有過載,我們就可以根據不同的引用型別,來選擇不同的過載函式,來完成不同的行為。回想一下,在上一講中,我們就利用了過載,讓 smart_ptr 的建構函式可以有不同的行為:

template

<

typename u>

smart_ptr

(const smart_ptr

& other)

noexcept

}template

<

typename u>

smart_ptr

(smart_ptr

&& other)

noexcept

}

看下面這段**:

smart_ptr ptr1

;smart_ptr ptr2 = std::

move

(ptr1)

;

第乙個表示式裡的 new circle() 就是乙個純右值;但對於指標,我們通常使用值傳遞,並不關心它是左值還是右值。

第二個表示式裡的 std::move(ptr) 就有趣點了。它的作用是把乙個左值引用強制轉換成乙個右值引用,而並不改變其內容。從實用的角度,在我們這兒 std::move(ptr1) 等價於 static_cast&&>(ptr1)。因此,std::move(ptr1) 的結果是指向 ptr1 的乙個右值引用,這樣構造 ptr2 時就會選擇上面第二個過載。

我們可以把 std::move(ptr1) 看作是乙個有名字的右值。為了跟無名的純右值 prvalue 相區別,c++ 裡目前就把這種表示式叫做 xvalue。跟左值 lvalue 不同,xvalue 仍然是不能取位址的——這點上,xvalue 和 prvalue 相同。所以,xvalue 和 prvalue 都被歸為右值 rvalue。我們用下面的圖來表示會更清楚一點:

C 移動語義和右值引用

移動語義類似於在計算機中移動檔案的情形 實際檔案還留在原來的地方,而只修改記錄。例如有乙個函式,它返回乙個vector物件 要實現移動語義,需要讓編譯器知道什麼時候需要複製,什麼時候不需要。這就是右值引用發揮作用的地方。可定義兩個建構函式,其中乙個是常規複製建構函式,它使用const左值引用作為引數...

右值引用和物件移動

c 包括 c 中所有的表示式和變數要麼是左值,要麼是右值。通俗的左值的定義就是非臨時物件,那些可以在多條語句中使用的物件。所有的變數都滿足這個定義,在多條 中都可以使用,都是左值。右值是指臨時的物件,它們只在當前的語句中有效。為了支援移動操作,c 11引入了一種新的引用型別 右值引用。就是必須繫結到...

右值引用和移動語義

在c 當中,所有的變數和表示式都被分為左值和右值。所謂的左值,就是可以被定址的非臨時變數。右值就是無法被定址的臨時變數。左值引用用 符號表示,右值引用用 符號表示。左值引用 int n int np new int const int cn 100 int nr n int npr np const...