當(dāng)前位置:首頁 > 公眾號精選 > CPP開發(fā)者
[導(dǎo)讀]↓推薦關(guān)注↓表達(dá)式是C語言的基石。每個(gè)表達(dá)式都有兩個(gè)屬性:類型(type)和值類別(valuecategory)。前者是大家都熟悉的,但是后者卻可能是我們不太在意的。本文的目的是介紹與值類別相關(guān)的一些知識。前言本文是C基礎(chǔ)系統(tǒng)文章中的一篇,將介紹C中的值類別,以及與之相關(guān)的一些概...

推薦關(guān)注↓

表達(dá)式是C 語言的基石。每個(gè)表達(dá)式都有兩個(gè)屬性:類型(type)和值類別(value category)。前者是大家都熟悉的,但是后者卻可能是我們不太在意的。本文的目的是介紹與值類別相關(guān)的一些知識。

前言

本文是C 基礎(chǔ)系統(tǒng)文章中的一篇,將介紹C 中的值類別,以及與之相關(guān)的一些概念。

表達(dá)式與值類別

C 的程序由一系列的表達(dá)式(expressions)構(gòu)成。表達(dá)式是運(yùn)算符和操作數(shù)的序列,表達(dá)式指定一項(xiàng)計(jì)算。

例如:2 2 或者 std::cout << "Hello World" << std::endl都是表達(dá)式。

每個(gè)表達(dá)式有兩個(gè)互相獨(dú)立但是非常重要的屬性:

  • 類型(type)。類型是我們很熟悉的概念,intdoublestd::string這些都是類型。類型確定了表達(dá)式可以進(jìn)行哪些操作。
  • 除了類型之外,還有一個(gè)稱之為值類別(value category)的屬性,卻可能是我們平時(shí)不太注意的。
type和category在中文中似乎都可以翻譯成“類型”。但在本文中,為了區(qū)分它們,統(tǒng)一將type翻譯成“類型”,category翻譯成“類別”。

為什么要懂這些東西?

不管你在不在意,每個(gè)表達(dá)式都屬于三種值類別(prvalue,xvalue,lvalue)中的一種。值類別可以影響表達(dá)式的含義,例如:你應(yīng)該知道這個(gè)表達(dá)式是沒有意義的:3 = 4,它甚至編譯不過。但你可能說不出來為什么編譯器會(huì)認(rèn)為它編譯不過。

如果你使用gcc編譯器,它的報(bào)錯(cuò)如下:

?error:?lvalue?required?as?left?operand?of?assignment
這個(gè)報(bào)錯(cuò)中的lvalue就是數(shù)字表達(dá)式3的值類別。

再者,值類別還會(huì)影響函數(shù)的重載:當(dāng)某個(gè)函數(shù)有兩種重載可用,其中之一接受右值引用的形參而另一個(gè)接受 const 的左值引用的形參時(shí),右值將被綁定到右值引用的重載之上。如果你不明白這里提到的“左值引用”和“右值”是指什么的話請不要擔(dān)心,這就是本文所要說明的。

從左值和右值說起

最初的時(shí)候,只有左值(lvalue)和右值(rvalue)這兩個(gè)術(shù)語。它們源于C 的祖先語言:[CPL](https://en.wikipedia.org/wiki/CPL_(programming_language "CPL"))。

lvalue之所以叫l(wèi)value,是因?yàn)樗33霈F(xiàn)在等號的左邊(left-hand side of an assignment)。同樣,rvalue是因?yàn)樗33霈F(xiàn)在等號的右邊(right-hand side of an assignment)。

回顧一下上面的3 = 4編譯報(bào)錯(cuò),就是因?yàn)榫幾g器要求等號的左邊得是一個(gè)lvalue,而數(shù)字3其實(shí)是一個(gè)rvalue,所以這個(gè)是無法通過編譯的。

C語言遵循了相似的分類法,但是否需要等號賦值已經(jīng)不再重要。在C語言中,標(biāo)識一個(gè)對象的表達(dá)式稱之為左值,不過lvalue已經(jīng)是“l(fā)ocator value”的簡寫,因?yàn)閘value對應(yīng)了一塊內(nèi)存地址。

你可以簡單的理解為:左值對應(yīng)了具有內(nèi)存地址的對象,而右值僅僅是臨時(shí)使用的值。例如int a = 1中,a是左值,1是右值。

C 11中的值類別

C 中對于值類別的定義也經(jīng)歷一些變化。從C 11標(biāo)準(zhǔn)開始,值類別早以不止是lvalue和rvalue兩種這么簡單。

但情況也不算太壞,因?yàn)橹饕闹殿悇e有:lvalue,prvalue 和 xvalue三種。加上兩種混合類別:glvalue和rvalue,一共有五種。

我們來看一下它們的定義:

  • A glvalue(generalized lvalue) is an expression whose evaluation determines the identity of an object, bit-field, or function.
  • A prvalue(pure rvalue) is an expression whose evaluation initializes an object or a bit-field, or computes the value of an operand of an operator, as specified by the context in which it appears, or an expression that has type cv void.
  • An xvalue(eXpiring value) is a glvalue that denotes an object or bit-field whose resources can be reused (usually because it is near the end of its lifetime).
  • An lvalue is a glvalue that is not an xvalue.
  • An rvalue is a prvalue or an xvalue.
這個(gè)定義很難理解,就算翻譯成中文,也一樣不好理解。所以下文會(huì)通過一些示例來對它們進(jìn)行說明。

這五種類別的分類基于表達(dá)式的兩個(gè)特征:

  • 是否擁有身份(identity):可以確定表達(dá)式是否與另一表達(dá)式指代同一實(shí)體,例如比較它們所標(biāo)識的對象或函數(shù)的(直接或間接獲得的)地址;
  • 是否可被移動(dòng)(具體見下文):移動(dòng)構(gòu)造函數(shù)、移動(dòng)賦值運(yùn)算符或?qū)崿F(xiàn)了移動(dòng)語義的其他函數(shù)重載能夠綁定到這個(gè)表達(dá)式。
由此,C 11中對于這五種類別定義如下:

  • lvalue是指:擁有身份且不可被移動(dòng)的表達(dá)式。
  • xvalue是指:擁有身份且可被移動(dòng)的表達(dá)式。
  • prvalue是指:不擁有身份且可被移動(dòng)的表達(dá)式。
  • glvalue是指:擁有身份的表達(dá)式,lvalue和xvalue都是glvalue。
  • rvalue是指:可被移動(dòng)的表達(dá)式。prvalue和xvalue都是rvalue。
這么說起來還是有些拗口,不過其實(shí)顛來倒去就是兩個(gè)特征的“是”與“否”,所以通過一個(gè)2x2的表格就很容易描述清楚了:


擁有身份(glvalue)不擁有身份
可移動(dòng)(rvalue)xvalueprvalue
不可移動(dòng)lvalue不存在
注:不存在不擁有身份也不可移動(dòng)的表達(dá)式。

我們可以通過下面這個(gè)圖來記憶五種類別的關(guān)系:

img
每種值類別都有其關(guān)聯(lián)的性質(zhì),這些性質(zhì)決定了表達(dá)式可以如何使用。

glvalue

glvalue是擁有身份的表達(dá)式,它對應(yīng)了一塊內(nèi)存地址。glvalue有l(wèi)value和xvalue兩種形式,具體的示例見下文。

glvalue具有以下一些特性:

  • glvalue可以自動(dòng)轉(zhuǎn)換成prvalue。例如:int a = b,等號右邊的lvalue會(huì)自動(dòng)轉(zhuǎn)換成rvalue。
  • glvalue可以是多態(tài)的(polymorphic),它所對應(yīng)了動(dòng)態(tài)類型和靜態(tài)類型可以不一樣,例如:一個(gè)指向子類的父類指針。
  • glvalue可以是不完整類型,只要表達(dá)式允許。例如:由前置聲明但未定義的類類型。

rvalue

rvalue是指可以移動(dòng)的表達(dá)式。prvalue和xvalue都是rvalue,具體的示例見下文。

rvalue具有以下特征:

  • 無法對rvalue進(jìn)行取地址操作。例如:
本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉