亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解C++中的左值,純右值和將亡值

 更新時間:2022年09月27日 08:40:32   作者:Mi?ronin  
C++中本身是存在左值,右值的概念,但是在C11中又出現(xiàn)了左值,純右值,將亡值得概念;這里我們主要介紹這些值的概念,感興趣的可以了解一下

引入

C++中本身是存在左值,右值的概念,但是在C11中又出現(xiàn)了左值,純右值,將亡值得概念;這里我們主要介紹這些值的概念。

一.表達式

定義:由運算符和運算對象構(gòu)成的計算式(類似數(shù)學(xué)中的算術(shù)表達式)

每個 C++ 表達式(帶有操作數(shù)的操作符、字面量、變量名等)可按照兩種獨立的特性加以辨別:**類型和值類別 **(value category)。每個表達式都具有某種非引用類型,且每個表達式只屬于三種基本值類別中的一種:純右值 (prvalue)、亡值 (xvalue)、左值 (lvalue)。

二.值類別

對于表達式來說:表達式是可以求值的,對表達式求值將得到一個結(jié)果,這個結(jié)果有兩個屬性:類型和值類別。

在C++11以后表達式按值類別分類,必然屬于以下三者之一:

  • 左值
  • 將亡值
  • 純右值

其中,左值和將亡值合稱為泛左值,純右值和將亡值合稱為右值

三.左值

左值:能夠用&取地址的表達式為左值表達式

下列表達式是左值表達式:

  1. 變量、函數(shù)、模板形參對象 (C++20 起)或數(shù)據(jù)成員的名字,不論類型,例如 std::cin 或 std::endl。即使變量的類型是右值引用,由它的名字構(gòu)成的表達式仍是左值表達式;
  2. 返回類型是左值引用的函數(shù)調(diào)用或重載運算符表達式,例如 std::getline(std::cin, str)、std::cout << 1、str1 = str2 或 ++it;
  3. a = b,a += b,a %= b,以及所有其他內(nèi)建的賦值及復(fù)合賦值表達式;
  4. ++a 和 --a,內(nèi)建的前置自增與前置自減表達式;
  5. *p,內(nèi)建的間接尋址表達式;
  6. a[n] 和 n[a],內(nèi)建的下標表達式,當 a[n] 中的一個操作數(shù)是數(shù)組左值時 (C++11 起);
  7. a.m,對象成員表達式,除了 m 是成員枚舉項或非靜態(tài)成員函數(shù),或者 a 是右值而 m 是對象類型的非靜態(tài)數(shù)據(jù)成員的情況;
  8. p->m,內(nèi)建的指針成員表達式,除了 m 是成員枚舉項或非靜態(tài)成員函數(shù)的情況;
  9. a.*mp,對象的成員指針表達式,其中 a 是左值且 mp 是數(shù)據(jù)成員指針;
  10. p->*mp,內(nèi)建的指針的成員指針表達式,其中 mp 是數(shù)據(jù)成員指針;
  11. a, b,內(nèi)建的逗號表達式,其中 b 是左值;
  12. a ? b : c,對某些 b 和 c 的三元條件表達式(例如,當它們都是同類型左值時,但細節(jié)見定義);
  13. 字符串字面量,例如 “Hello, world!”;
  14. 轉(zhuǎn)換到左值引用類型的轉(zhuǎn)型表達式,例如 static_cast<int&>(x);
  15. 返回類型是到函數(shù)的右值引用的函數(shù)調(diào)用表達式或重載的運算符表達式;(C++11 起)
  16. 轉(zhuǎn)換到函數(shù)的右值引用類型的轉(zhuǎn)型表達式,如 static_cast<void (&&)(int)>(x)。(C++11 起)

性質(zhì):

  1. 可以通過內(nèi)建的取址運算符取左值的地址:&++i[1] 及 &std::endl 是合法表達式。
  2. 可修改的左值可用作內(nèi)建賦值和內(nèi)建復(fù)合賦值運算符的左操作數(shù)。
  3. 左值可以用來初始化左值引用;這會將一個新名字關(guān)聯(lián)給該表達式所標識的對象。

四.純右值

滿足下列條件之一:

1.本身就是純粹的字面值,如3,false,12.13

2.求值結(jié)果相當于字面值或是一個不具名的臨時對象

下列表達式是純右值表達式:

  1. (除了字符串字面量之外的)字面量,例如 42、true 或 nullptr;
  2. 返回類型是非引用的函數(shù)調(diào)用或重載運算符表達式,例如 str.substr(1, 2)、str1 + str2 或 it++;
  3. a++ 和 a–,內(nèi)建的后置自增與后置自減表達式;
  4. a + b、a % b、a & b、a << b,以及其他所有內(nèi)建的算術(shù)表達式;
  5. a && b、a || b、!a,內(nèi)建的邏輯表達式;
  6. a < b、a == b、a >= b 以及其他所有內(nèi)建的比較表達式;
  7. &a,內(nèi)建的取地址表達式;
  8. a.m,對象成員表達式,其中 m 是成員枚舉項或非靜態(tài)成員函數(shù)[2],或其中 a 是右值且 m 是非- - 引用類型的非靜態(tài)數(shù)據(jù)成員 (C++11 前);
  9. p->m,內(nèi)建的指針成員表達式,其中 m 是成員枚舉項或非靜態(tài)成員函數(shù)[2];
  10. a.*mp,對象的成員指針表達式,其中 mp 是成員函數(shù)指針[2],或其中 a 是右值且 mp 是數(shù)據(jù)成員指針 (C++11 前);
  11. p->*mp,內(nèi)建的指針的成員指針表達式,其中 mp 是成員函數(shù)指針[2];
  12. a, b,內(nèi)建的逗號表達式,其中 b 是右值;
  13. a ? b : c,對某些 b 和 c 的三元條件表達式(細節(jié)見定義);
  14. 轉(zhuǎn)換到非引用類型的轉(zhuǎn)型表達式,例如 static_cast(x)、std::string{} 或 (int)42;
  15. this 指針;
  16. 枚舉項;
  17. 非類型模板形參,除非它的類型是類或 (C++20 起)左值引用類型;
  18. lambda 表達式,例如 [](int x){ return x * x; };(C++11 起)
  19. requires 表達式,例如 requires (T i) { typename T::type; };(C++20 起)
  20. 概念的特化,例如 std::equality_comparable (C++20 起)

性質(zhì):

純右值不具有多態(tài):它所標識的對象的動態(tài)類型始終是該表達式的類型。

非類非數(shù)組的純右值不能有 cv 限定,除非它被實質(zhì)化以綁定到 cv 限定類型的引用 (C++17 起)。(注意:函數(shù)調(diào)用或轉(zhuǎn)型表達式可能生成非類的 cv 限定類型的純右值,但它的 cv 限定符通常被立即剝除。)

純右值不能具有不完整類型(除了類型 void(見下文),或在 decltype 說明符中使用之外)

純右值不能具有抽象類類型或它的數(shù)組類型。

易混:

++i是左值,i++是右值

前者,對i加1后再賦給i,最終的返回值就是i,所以,++i的結(jié)果是具名的,名字就是i;而對于i++而言,是先對i進行一次拷貝,將得到的副本作為返回結(jié)果,然后再對i加1,由于i++的結(jié)果是對i加1前i的一份拷貝,所以它是不具名的。

假設(shè)自增前i的值是6,那么,++i得到的結(jié)果是7,這個7有個名字,就是i;而i++得到的結(jié)果是6,這個6是i加1前的一個副本,它沒有名字,i不是它的名字,i的值此時也是7??梢姡?+i和i++都達到了使i加1的目的,但兩個表達式的結(jié)果不同。

解引用表達式 * p是左值,取地址表達式 &a 是純右值。

&(*p) 一定是正確的,因為 *p得到的是p指向的實體,&( *p)得到的就是這一實體的地址,正是p的值。由于 &(*p)的正確,所以 *p是左值。而對&a而言,得到的是a的地址,相當于unsigned int型的字面值,所以是純右值。

a+b、a&&b、ab 都是純右值

a+b得到的是不具名的臨時對象,而 a&&b 和 ab 的結(jié)果非 true 即 false,相當于字面值。

五.將亡值

在C++11之前的右值和C++11中的純右值是等價的。C++11中的將亡值是隨著右值引用的引入而新引入的。換言之,“將亡值”概念的產(chǎn)生,是由右值引用的產(chǎn)生而引起的,將亡值與右值引用息息相關(guān)。所謂的將亡值表達式,就是下列表達式:

  • 返回右值引用的函數(shù)的調(diào)用表達式
  • 轉(zhuǎn)換為右值引用的轉(zhuǎn)換函數(shù)的調(diào)用表達式

在C++11中,我們用左值去初始化一個對象或為一個已有對象賦值時,會調(diào)用拷貝構(gòu)造函數(shù)或拷貝賦值運算符來拷貝資源(所謂資源,就是指new出來的東西),而當我們用一個右值(包括純右值和將亡值)來初始化或賦值時,會調(diào)用移動構(gòu)造函數(shù)或移動賦值運算符來移動資源,從而避免拷貝,提高效率。當該右值完成初始化或賦值的任務(wù)時,它的資源已經(jīng)移動給了被初始化者或被賦值者,同時該右值也將會馬上被銷毀(析構(gòu))。

也就是說,當一個右值準備完成初始化或賦值任務(wù)時,它已經(jīng)“將亡”了。而上面1)和2)兩種表達式的結(jié)果都是不具名的右值引用,它們屬于右值。

又因為

1)這種右值是與C++11新生事物——“右值引用”相關(guān)的“新右值”

2)這種右值常用來完成移動構(gòu)造或移動賦值的特殊任務(wù),扮演著“將亡”的角色,所以C++11給這類右值起了一個新的名字——將亡值。

下列表達式是將亡值表達式:

  1. 返回類型為對象的右值引用的函數(shù)調(diào)用或重載運算符表達式,例如 std::move(x);
  2. a[n],內(nèi)建的下標表達式,它的操作數(shù)之一是數(shù)組右值;
  3. a.m,對象成員表達式,其中 a 是右值且 m 是非引用類型的非靜態(tài)數(shù)據(jù)成員;
  4. a.*mp,對象的成員指針表達式,其中 a 是右值且 mp 是數(shù)據(jù)成員指針;
  5. a ? b : c,對某些 b 和 c 的三元條件表達式(細節(jié)見定義);
  6. 轉(zhuǎn)換到對象的右值引用類型的轉(zhuǎn)型表達式,例如 static_cast<char&&>(x);
  7. 在臨時量實質(zhì)化后,任何指代該臨時對象的表達式。(C++17 起)

性質(zhì):

1.與右值相同。

2.與泛左值相同。

特別是,與所有的右值類似,亡值可以綁定到右值引用上,而且與所有的泛左值類似,亡值可以是多態(tài)的,而且非類的亡值可以有 cv 限定。

六.注意

1)字符串字面值是左值。

不是所有的字面值都是純右值,字符串字面值是唯一例外。

早期C++將字符串字面值實現(xiàn)為char型數(shù)組,實實在在地為每個字符都分配了空間并且允許程序員對其進行操作,

cout<<&("abc")<<endl;
const char *p_char="abc";//注意不是char *p_char=&("abc");

這樣的代碼都是可以編譯通過的。

2)具名的右值引用是左值,不具名的右值引用是右值。

void foo(X&& x) 
{ 
    X anotherX = x; //后面還可以訪問x
}

上面X是自設(shè)計的類型,并且,其有一個指針成員p指向了在堆中分配的內(nèi)存;參數(shù)x是X的右值引用。如果將x視為右值,那么,X another X = x;一句將調(diào)用X類的移動構(gòu)造函數(shù),而我們知道,這個移動構(gòu)造函數(shù)的主要工作就是將x的p指針的值賦給anotherX的p指針,然后將x的p指針置為nullptr。而在后面,我們還可以訪問x,也就是可以訪問x.p,而此時x.p已經(jīng)變成了nullptr,這就可能發(fā)生意想不到的錯誤。

3)注釋

①只有當存在兩個或兩個以上的運算對象時才需要運算符連接,單獨的運算對象也可以是表達式,例如上面提到的字面值和變量。

②確切說,是表達式的結(jié)果的值類別,但我們一般不刻意區(qū)分表達式和表達式的求值結(jié)果,所以這里稱“表達式的值類別”。

③當我們將函數(shù)名作為一個值來使用時,該函數(shù)名自動轉(zhuǎn)換為指向?qū)?yīng)函數(shù)的指針。

④關(guān)于右值引用本身,沒什么可說的,就是指可以綁定到右值上的引用,用"&&"表示,如int&&rra=6;。相比之下,與右值引用相關(guān)的一些主題,如移動語義、引用疊加、完美轉(zhuǎn)發(fā)等,更值得我們深入探討。這些內(nèi)容,在下在后續(xù)文章中都會詳細介紹。

⑤前提是該右值(如自定義的類X)有移動構(gòu)造函數(shù)或移動賦值運算符可供調(diào)用(有時候是沒有的,關(guān)于這些知識,后續(xù)文章在講移動構(gòu)造函數(shù)和移動賦值運算符時會詳述)。

⑥在本文的例二中,如果將get_a_X()的返回值由X的右值引用改為X對象,則get_a_X()是純右值表達式(如前所述,返回非引用類型的函數(shù)調(diào)用是純右值),此時Foo(get_a_X());一句調(diào)用的仍然是類X的移動構(gòu)造函數(shù),這就是一個純右值完成移動構(gòu)造的例子。

到此這篇關(guān)于詳解C++中的左值,純右值和將亡值的文章就介紹到這了,更多相關(guān)C++值內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++模板特例化應(yīng)用實例

    C++模板特例化應(yīng)用實例

    這篇文章主要介紹了C++模板特例化應(yīng)用實例,是非常重要的一個概念,需要的朋友可以參考下
    2014-08-08
  • 詳解原碼、反碼與補碼存儲與大小

    詳解原碼、反碼與補碼存儲與大小

    這篇文章主要介紹了詳解原碼、反碼與補碼存儲與大小的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • 圖解C++的STL之stack和queue,輕松理解數(shù)據(jù)結(jié)構(gòu)

    圖解C++的STL之stack和queue,輕松理解數(shù)據(jù)結(jié)構(gòu)

    聚焦?C++?的?STL?中的?stack?和?queue,讓數(shù)據(jù)結(jié)構(gòu)變得簡單有趣!?通過圖解的方式,我們將輕松理解這兩個重要的數(shù)據(jù)結(jié)構(gòu),準備好開啟?STL?學(xué)習(xí)之旅了嗎?讓我們一起探索?stack?和?queue?的奧秘吧!
    2024-03-03
  • 使用C語言繪制柱形圖的示例代碼

    使用C語言繪制柱形圖的示例代碼

    常用的統(tǒng)計圖有條形圖、柱形圖、折線圖、曲線圖、餅圖、環(huán)形圖、扇形圖,這篇文章主要為大家介紹了C語言中繪制條形圖和柱形圖的方法,需要的可以參考下
    2024-02-02
  • C++類的定義和對象的創(chuàng)建詳解

    C++類的定義和對象的創(chuàng)建詳解

    本篇文章重點講解了兩種創(chuàng)建對象的方式:一種是在棧上創(chuàng)建,形式和定義普通變量類似;另外一種是在堆上使用 new 關(guān)鍵字創(chuàng)建,必須要用一個指針指向它,下面和小編一起來學(xué)習(xí)下面為文章的內(nèi)容
    2021-09-09
  • C語言之malloc動態(tài)分配內(nèi)存和free釋放

    C語言之malloc動態(tài)分配內(nèi)存和free釋放

    這篇文章主要介紹了C語言之malloc動態(tài)分配內(nèi)存和free釋放,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 詳解Dijkstra算法原理及其C++實現(xiàn)

    詳解Dijkstra算法原理及其C++實現(xiàn)

    Dijkstra算法用于計算一個節(jié)點到其他節(jié)點的最短路徑。Dijkstra是一種按路徑長度遞增的順序逐步產(chǎn)生最短路徑的方法,是一種貪婪算法。本文將詳解Dijkstra算法原理及其C++實現(xiàn),感興趣的可以了解一下
    2022-07-07
  • C語言中形參和實參詳解及實例代碼

    C語言中形參和實參詳解及實例代碼

    這篇文章主要介紹了C語言中形參和實參詳解及實例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • OpenCV和C++實現(xiàn)圖像的翻轉(zhuǎn)(鏡像)、平移、旋轉(zhuǎn)、仿射與透視變換

    OpenCV和C++實現(xiàn)圖像的翻轉(zhuǎn)(鏡像)、平移、旋轉(zhuǎn)、仿射與透視變換

    這篇文章主要給大家介紹了關(guān)于OpenCV和C++實現(xiàn)圖像的翻轉(zhuǎn)(鏡像)、平移、旋轉(zhuǎn)、仿射與透視變換的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-09-09
  • 用QT實現(xiàn)計時器功能

    用QT實現(xiàn)計時器功能

    這篇文章主要為大家詳細介紹了用QT實現(xiàn)計時器功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評論