C 右值引用

2021-10-22 18:26:47 字數 2791 閱讀 3005

c++11 中引用的乙個重要 feature 便是右值引用,在介紹右值引用之前我們首先理解一下左值和右值的概念。

簡單理解的話,在 c++ 中可以取位址的、有名字的值是左值,不能取位址、沒有名字的值則是右值。

// 變數 a 有名字,可以取位址(&a),是左值

// 字面量 0 沒有名字,不能取位址(&0 是非法的),所以 0 是右值

int a = 0;

int b = 1; // b 是左值,1 是右值

// 變數 c 有名字,可以取位址(&b),是左值

// a + b 不能取位址(&(a+b) 是非法的),所以 a + b 是右值

int c = a + b;

// 函式 foo 的返回值是右值,因為無法獲得返回值所占用的具體記憶體位址,&foo() 是非法的

int foo()

了解了左值和右值的概念,下面來思考一下為什麼 c++11 需要單獨的引入一種新的型別:右值引用型別呢?

讓我們先回到 c++11 之前的標準即 c++98,了解了 c++98 中規則的不足之處,便能進一步理解為什麼 c++11 需要單獨引入右值引用這一 feature。

在 c++98 的語法中,只有左值引用型別,考慮 const 修飾符的話可以細分為非常量左值引用和常量左值引用,下面的**規定了左值引用的繫結規則:

非常量左值

常量左值

非常量右值

常量右值

註記非常量左值引用yn

nn無常量左值引用yy

yy全能型別

其中非常量左值引用只能繫結到非常量左值,而常量左值引用可以繫結到任意的 const/non const 左值或右值。下面是乙個具體的**示例來更好的理解這一概念:

int a = 0;    // a 是非常量左值

const int b = 0; // b 是常量左值

int foo() // foo 函式的返回值是非常量右值

const int bar() // bar 函式的返回值是常量右值

// 下面考慮非常量左值引用的繫結規則

int& c0 = a; // 合法,非常量左值引用 c0 可以繫結到非常量左值 a

int& c1 = b; // 非法,非常量左值引用 c1 不能繫結到常量左值 b

int& c2 = foo(); // 非法,非常量左值引用 c2 不能繫結到非常量右值

int& c3 = bar(); // 非法,非常量左值引用 c3 不能繫結到常量右值

// 常量左值引用可以繫結到任意(非)常量左值或右值

const int& d0 = a; // 合法

const int& d1 = b; // 合法

const int& d2 = foo(); // 合法

const int& d3 = bar(); // 合法

現在假設有以下**:

class largeobject;

// construct 構造乙個 largeobject 物件

largeobject construct()

void process(x obj)

process(construct()); // 函式呼叫 [1]

construct 函式返回乙個 largeobject 物件,process 函式需要處理乙個 largeobject 物件,且可能改寫該物件的資料,那麼 x 具體應該是什麼型別呢?首先 x 是 largeobject 是不合理的,因為這需要進行一次拷貝,我們希望 x 是引用來減少拷貝開銷。

在函式呼叫 [1] 處,construct() 函式返回的是乙個右值,所以 x 是 largeobject& 是非法的,因為非常量左值引用是不能繫結到右值的,那麼 x 能是 const largeobject& 嗎?此時常量左值引用確實能繫結到右值,但是在 process 函式內部卻無法改寫 obj 的內容了,因為 obj 是 const 引用,在 process 函式內只能讀 obj 的內容而不能寫 obj 的內容。所以無論 x 是非常量左值引用還是常量左值引用,[1] 處的函式呼叫都不滿足我們的目的。

所以 c++11 引入了一種新的引用型別,即右值引用型別,並擴充引用了繫結規則:

非常量左值

常量左值

非常量右值

常量右值

註記非常量左值引用yn

nn無常量左值引用yy

yy全能型別,可用於拷貝型別

非常量右值引用nn

yn用於移動語義、完美**

常量右值引用nn

yy暫無用途

可以看到此時非常量右值引用是可以繫結到非常量右值的,所以在 c++11 中 process 可以改寫成以下**:

void process(largeobject&& obj) 

process(construct());

在 c++ **中經常會產生一些右值物件,而我們也希望引用能繫結到該右值物件並進行寫操作,而在 c++98 的語法規則中,只有 const 左值引用能繫結到非常量右值,但此時引用是 const 的,我們便缺失了通過該 const 引用對右值進行改寫的能力。所以 c++11 中引用了右值引用,並且規定非常量右值引用也能繫結到非常量右值,便完美解決了我們的需求。

在後面的文章中,會更進一步的介紹右值引用的兩個最主要的功能:移動語義和完美**。

c 左值 右值 右值引用 左值引用

c 裡一切值必須屬於左值 右值兩者之一。左值 一切變數 包括用const修飾的變數 物件 包括引用都屬於左值 右值 一切字面值 可以是巨集 臨時無名物件 函式返回值 表示式 如a n 說明一下 函式返回值,返回的是某乙個型別的值,並不是返回變數。左值並不是說能放在 左邊的值就是左值 雖然用const...

c 左值 右值 左值引用 右值引用

在c語言中,左值認為是賦值語句的左側,右值認為是賦值語句的右側。在c 中,意義稍有不同。c 中,每乙個表示式會產生乙個左值或者右值,相應的,該表示式也就被稱作 左值表示式 右值表示式 乙個左值表示式的求值結果是乙個物件或者是乙個函式。左值可以當右值使用,而右值不能當左值使用。c prime 中這麼簡...

C 左值 右值 左值引用 右值引用

就變數而言,對於一些變數,我們只會讀取並使用它們的值,而不會改變他們的值 唯讀 對於其餘的變數,我們既會讀取它們的值,有的時候還會改變它們的值 讀寫 這是很常見的。在c 中,前一種變數稱為右值,後一種變數稱為左值,例如 int a 1 a是左值,1是右值稍稍不同的一點是,在c 中,乙個變數是左值還是...