日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

的引用_左值、右值、左值引用、右值引用

發布時間:2023/12/10 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 的引用_左值、右值、左值引用、右值引用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【導讀】:本文主要詳細介紹了左值、右值、左值引用、右值引用以及move、完美轉發。

左值和右值

左值(left-values),縮寫:lvalues

右值(right-values),縮寫:rvalues

直接上官網查,我一向倡導自己去懂得原理,而原理都是老外寫的,當然我只是針對c 編程語言這樣說。

https://msdn.microsoft.com/en-us/library/f90831hc.aspx

翻譯:所有的c 表達,不是左值就是右值。

  • lvalues是指存在于單個表達式之外的對象。你可以把左值當成有名字的對象。所有的變量,包括常變量,都是左值。

  • rvalues是一個暫時存在的值存在于單個表達式之內的對象。

有點拗口(難理解),通俗來說就是,左值的生存期不只是這句話,后面還能用到它。

而右值呢,出了這句話就掛了,所以也叫(將亡值)。

它舉了一個栗子:

#include???
using?namespace?std;??
int?main()??{??
???int?x?=?3? ?4;??
???cout?<endl;??
}??

在以上實例中,很顯然,x是左值,3 4是右值。

它又舉了一個栗子,來說明錯誤的使用和正確的使用

//?lvalues_and_rvalues2.cpp??
int?main()??{??
???int?i,?j,?*p;??
??
???//?正確的使用:?變量是左值?
???i?=?7;??
??
???//?錯誤的使用:?左邊的操作?必須是?左值?(C2106)
???7?=?i;?//?C2106??
???j?*?4?=?7;?//?C2106??
??
???//?正確的使用:?被間接引用的指針是左值
???*p?=?i;???
??
???const?int?ci?=?7;??
???//?錯誤的使用:?左邊的操作?是?常量左值?(C3892)
???ci?=?9;?//?C3892?
??
???//?正確的使用:?條件操作?返回了左值
???((i?3)???i?:?j)?=?7;??
}??

左值引用、右值引用

左值引用:參考說明書《Lvalue Reference Declarator: &》,網站如下:

https://msdn.microsoft.com/en-us/library/w7049scy.aspx

使用語法:類型 &(引用符) 表達式

type-id?&?cast-expression?

翻譯:

你可以把左值引用當成對象的另一個名字,lvalue引用聲明由一個可選的說明符列表和一個引用聲明符組成。

引用必須初始化,而且不能改變。

一個對象的地址可以 轉化成 一種指定類型的指針 或者 轉化成 一個 相似類型的引用。意義是相同的。

demo:

char?c_val?=?'c';
char?*ptr?=?&c_val;
char?&r_val?=?c_val;

不要混淆 取地址 和 引用,當&說明符前面帶有類型聲明,則是引用,否則就是取地址。

通俗來說 &在 ”=” 號左邊的是引用,右邊的是取地址。

右值引用:參考說明書《Rvalue Reference Declarator: &&》,網站如下:

https://msdn.microsoft.com/en-us/library/dd293668.aspx

使用語法:類型 && 表達式

type-id?&&?cast-expression??

翻譯:

Move Semantics:移動語義

右值引用使您能夠區分左值和右值。Lvalue引用和rvalue引用在語法和語義上是相似的。

右值引用支持移動語義的實現,可以顯著提升應用程序的性能。移動語義允許您編寫將資源(例如動態分配的內存)從一個對象傳輸到另一個對象的代碼,移動語義行之有效,因為它允許從程序中其他地方無法引用的臨時對象轉移資源。

為了實現移動語義,你在類中提供一個動態構造,和可選擇的動態賦值運算符(operator=)。拷貝和賦值操作的資源是右值的可以自動調用移動語義。不像缺省的拷貝構造,編譯器并不提供缺省的動態構造。

demo:

#include???
#include???
using?namespace?std;??
??
int?main()??{??
???string?s?=?string("h")? ?"e"? ?"ll"? ?"o";??
???cout?<endl;??
}??

在Visual C 2010之前,每個調用 “ ”運算符會分配和返回一個新的臨時的string對象,

“ ”運算符不能從一個string擴展到另一個,因為它不知道string是左值還是右值。如果源字符串都是lvalues,那么它們可能在程序的其他地方被引用,因此不能被修改。通過使用右值引用“ ”運算符能夠修改那些不能在程序中別處引用的右值,所以現在“ ”運算符可以有一個string擴展到另一個。這可以顯著減少字符串類必須執行的動態內存分配的數量。

為了更好地理解移動語義,考慮向向量對象插入一個元素的例子。如果超出了vector對象的容量,vector對象必須為其元素重新分配內存,然后將每個元素復制到另一個內存位置,以便為插入的元素騰出空間。當插入操作復制一個元素時,它創建一個新元素,調用copy構造函數將數據從前一個元素復制到新元素,然后銷毀前一個元素。移動語義允許您直接移動對象,而不必執行昂貴的內存分配和復制操作。

Perfect Forwarding:完美轉發

完美的轉發減少了重載函數 避免了轉發的問題。轉發的問題出現在你寫通用函數將引用作為參數,將這些參數由函數調用的時候。

舉個例子,如果通用函數將 type const T&作為參數,那么調用函數不能修改參數的值。

如果通用函數 將 type T&作為參數,那么當參數是右值的時候,函數不能調用。

通常來說,為了解決上述的問題,你需要提供重載函數,既要有type const T&參數的函數,也要有type T&參數的函數。

結果呢,重載函數的數量隨著參數數量呈指數遞增。而右值引用能夠使你只用一個函數就能適用于任意數量的參數。

原先的做法如下:

先寫出所有適用的通用函數

struct?W??
{??
???W(int&,?int&)?{}??
};??
??
struct?X??
{??
???X(const?int&,?int&)?{}??
};??
??
struct?Y??
{??
???Y(int&,?const?int&)?{}??
};??
??
struct?Z??
{??
???Z(const?int&,?const?int&)?{}??
};??

再將帶有不同類型的參數的函數用模板結合起來

template?<typename?T,?typename?A1,?typename?A2>??
T*?factory(A1&?a1,?A2&?a2)??{??
???return?new?T(a1,?a2);??
}??

調用:需要根據適用的類型用相應的指針對接。

當調用的是左值時

int?a?=?4,?b?=?5;??
W*?pw?=?factory(a,?b);??

當調用的是右值時。但是,下面的示例中沒有包含對工廠函數的有效調用,因為工廠將可修改的lvalue引用作為其參數,但是它是通過使用右值調用的:

這里要注意的是const int &是lvalue 而不是 rvalue

而2是rvalue,函數會編譯不過。

Z*?pz?=?factory(2,?2);??

為了解決這類問題,需要將模板函數修改成如下形式,右值引用可以適用const T& 和 T&形式的參數:

template?<typename?T,?typename?A1,?typename?A2>??
T*?factory(A1&&?a1,?A2&&?a2)??{??
???return?new?T(std::forward(a1),?std::forward(a2));??
}??

經過上述修改,均可以調用,如下圖代碼所示:

總結

以上是生活随笔為你收集整理的的引用_左值、右值、左值引用、右值引用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。