C++11右值引用(一看即懂)

C++11是什麼》一節中提到,在 C++98/03 標準的基礎上,C++11 標準對 C++ 語言增添了約 140 個新特性。本節要講的右值引用就是衆多新特性中的一個,同時也是最重要的特性之一。

很多初學者都感覺右值引用晦澀難懂,其實不然。右值引用只不過是一種新的 C++ 語法,真正理解起來有難度的是基於右值引用引申出的 2 種 C++ 編程技巧,分別爲移動語義和完美轉發。本節先給讀者講解什麼是右值引用以及它的基本用法,至於移動語義和完美轉發則放到後續章節講解。

C++左值和右值

右值引用可以從字面意思上理解,指的是以引用傳遞(而非值傳遞)的方式使用 C++ 右值。關於 C++ 引用,已經在《C++引用》專題給大家做了詳細的講解,這裏不再重複贅述。接下來重點給大家介紹什麼是 C++ 右值。

在 C++ 或者 C 語言中,一個表達式(可以是字面量、變量、對象、函數的返回值等)根據其使用場景不同,分爲左值表達式和右值表達式。確切的說 C++ 中左值和右值的概念是從 C 語言繼承過來的。


值得一提的是,左值的英文簡寫爲“lvalue”,右值的英文簡寫爲“rvalue”。很多人認爲它們分別是"left value"、"right value" 的縮寫,其實不然。lvalue 是“loactor value”的縮寫,可意爲存儲在內存中、有明確存儲地址(可尋址)的數據,而 rvalue 譯爲 "read value",指的是那些可以提供數據值的數據(不一定可以尋址,例如存儲於寄存器中的數據)。

通常情況下,判斷某個表達式是左值還是右值,最常用的有以下 2 種方法。

1) 可位於賦值號(=)左側的表達式就是左值;反之,只能位於賦值號右側的表達式就是右值。舉個例子:

int a = 5;
5 = a; //錯誤,5 不能爲左值

其中,變量 a 就是一個左值,而字面量 5 就是一個右值。值得一提的是,C++ 中的左值也可以當做右值使用,例如:

int b = 10; // b 是一個左值
a = b; // a、b 都是左值,只不過將 b 可以當做右值使用


2) 有名稱的、可以獲取到存儲地址的表達式即爲左值;反之則是右值。

以上面定義的變量 a、b 爲例,a 和 b 是變量名,且通過 &a 和 &b 可以獲得他們的存儲地址,因此 a 和 b 都是左值;反之,字面量 5、10,它們既沒有名稱,也無法獲取其存儲地址(字面量通常存儲在寄存器中,或者和代碼存儲在一起),因此 5、10 都是右值。 


注意,以上 2 種判定方法只適用於大部分場景。由於本節主要講解右值引用,因此這裏適可而止,不再對 C++ 左值和右值做深度剖析,感興趣的讀者可自行研究。

C++右值引用

前面提到,其實 C++98/03 標準中就有引用,使用 "&" 表示。但此種引用方式有一個缺陷,即正常情況下只能操作 C++ 中的左值,無法對右值添加引用。舉個例子:

int num = 10;int &b = num; //正確int &c = 10; //錯誤

如上所示,編譯器允許我們爲 num 左值建立一個引用,但不可以爲 10 這個右值建立引用。因此,C++98/03 標準中的引用又稱爲左值引用

注意,雖然 C++98/03 標準不支持爲右值建立非常量左值引用,但允許使用常量左值引用操作右值。也就是說,常量左值引用既可以操作左值,也可以操作右值,例如:

int num = 10;const int &b = num;const int &c = 10;

我們知道,右值往往是沒有名稱的,因此要使用它只能藉助引用的方式。這就產生一個問題,實際開發中我們可能需要對右值進行修改(實現移動語義時就需要),顯然左值引用的方式是行不通的。

爲此,C++11 標準新引入了另一種引用方式,稱爲右值引用,用 "&&" 表示。

話說,C++標準委員會在選定右值引用符號時,既希望能選用現有 C++ 內部已有的符號,還不能與 C++ 98 /03 標準產生衝突,最終選定了 2 個 '&' 表示右值引用。

需要注意的,和聲明左值引用一樣,右值引用也必須立即進行初始化操作,且只能使用右值進行初始化,比如:

int num = 10;//int && a = num;  //右值引用不能初始化爲左值int && a = 10;

和常量左值引用不同的是,右值引用還可以對右值進行修改。例如:

int && a = 10;a = 100;cout << a << endl;

程序輸出結果爲 100。

另外值得一提的是,C++ 語法上是支持定義常量右值引用的,例如:

const int&& a = 10;//編譯器不會報錯

但這種定義出來的右值引用並無實際用處。一方面,右值引用主要用於移動語義和完美轉發,其中前者需要有修改右值的權限;其次,常量右值引用的作用就是引用一個不可修改的右值,這項工作完全可以交給常量左值引用完成。

學到這裏,一些讀者可能無法記清楚左值引用和右值引用各自可以引用左值還是右值,這裏給大家一張表格,方便大家記憶:




表 1 C++左值引用和右值引用
引用類型 可以引用的值類型 使用場景
非常量左值 常量左值 非常量右值 常量右值
非常量左值引用 Y N N N
常量左值引用 Y Y Y Y 常用於類中構建拷貝構造函數
非常量右值引用 N N Y N 移動語義、完美轉發
常量右值引用 N N Y Y 無實際用途


表中,Y 表示支持,N 表示不支持。

其實,C++11 標準中對右值做了更細緻的劃分,分別稱爲純右值(Pure value,簡稱 pvalue)和將亡值(eXpiring value,簡稱 xvalue )。其中純右值就是 C++98/03 標準中的右值(本節中已經做了大篇幅的講解),而將亡值則指的是和右值引用相關的表達式(比如某函數返回的 T && 類型的表達式)。對於純右值和將亡值,都屬於右值,讀者知道即可,不必深究。

圖片


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章