[C++] : C++11 右值引用的理解

(一)什么是左值和右值?

????????傳統的C++語法中就有引用的語法,而C++11中新增了的右值引用語法特性,所以從現在開始我們 之前學習的引用就叫做左值引用。無論左值引用還是右值引用,都是給對象取別名

?1.左值

????????左值是一個表示數據的表達式(如變量名或解引用的指針),我們可以獲取它的地址+可以對它賦值,左值可以出現賦值符號的左邊,右值不能出現在賦值符號左邊。定義時const修飾符后的左 值不能給他賦值,但是可以取它的地址。左值引用就是給左值的引用,給左值取別名。

?特別注意:

? ? ? ? const修飾后的左值,不能給他賦值,但它依然是左值。

int main()
{// 以下的p、b、c、*p都是左值int* p = new int(0);int b = 1;const int c = 2;// 以下幾個是對上面左值的左值引用int*& rp = p;int& rb = b;const int& rc = c;int& pvalue = *p;return 0;
}

?2.右值

????????右值也是一個表示數據的表達式,如:字面常量、表達式返回值,函數返回值(這個不能是左值引 用返回)等等,右值可以出現在賦值符號的右邊,但是不能出現出現在賦值符號的左邊,右值不能取地址。右值引用就是對右值的引用,給右值取別名。

注意:

? ? ? ?引用右值是“&&“, 右值的引用是左值(例如下面中的rr1,rr2,rr3都是左值)。

double fmin(double x, double y)
{return x > y ? y : x;
}int main()
{double x = 1.1, y = 2.2;// 以下幾個都是常見的右值10;x + y;fmin(x, y);// 以下幾個都是對右值的右值引用int&& rr1 = 10;double&& rr2 = x + y;double&& rr3 = fmin(x, y);  //fmin函數會返回一個臨時變量,這個變量是右值// 這里編譯會報錯:error C2106: “=”: 左操作數必須為左值10 = 1;x + y = 1;fmin(x, y) = 1;return 0;
}

需要注意的是右值是不能取地址的,但是給右值取別名后,會導致右值被存儲到特定位置且可 以取到該位置的地址,也就是說例如:不能取字面量10的地址,但是rr1引用后,可以對rr1取地 址,也可以修改rr1。如果不想rr1被修改,可以用const int&& rr1 去引用,是不是感覺很神奇, 這個了解一下實際中右值引用的使用場景并不在于此,這個特性也不重要。 ?

int main()
{double x = 1.1, y = 2.2;int&& rr1 = 10;const double&& rr2 = x + y;rr1 = 20;rr2 = 5.5; ?// 報錯return 0;
}

?(二)左值引用與右值引用比較

1.左值引用:

????????1. 左值引用只能引用左值,不能引用右值。

????????2. 但是const左值引用既可引用左值,也可引用右值

int main()
{// 左值引用只能引用左值,不能引用右值。int a = 10;int& ra1 = a; ? // ra為a的別名//int& ra2 = 10; ? // 編譯失敗,因為10是右值// const左值引用既可引用左值,也可引用右值。const int& ra3 = 10;const int& ra4 = a;return 0;
}

2.右值引用:?

????????1. 右值引用只能右值,不能引用左值。

????????2. 但是右值引用可以move以后的左值。

int main()
{// 右值引用只能右值,不能引用左值。int&& r1 = 10;// error C2440: “初始化”: 無法從“int”轉換為“int &&”// message : 無法將左值綁定到右值引用int a = 10;int&& r2 = a;// 右值引用可以引用move以后的左值int&& r3 = std::move(a);//move(a)之后,a并不是轉換成了右值,a仍然為左值//(簡單的)可以理解為調用move函數,move返回了一個和a數據一摸一樣的右值。return 0;}

注意:

? ? ? ? move(a)并不是將a變成了左值,(可以這么理解)而是該函數返回了一個與a數據一樣匿名對象,但是對該右值進行操作會影響到a。

(三)?右值引用使用場景和意義

左值引用的短板:

????????當函數返回對象是一個局部變量,出了函數作用域就不存在了,就不能使用左值引用返回, 只能傳值返回。????????

????????例如下面的:bit::string to_string(int value)函數中可以看到,這里只能使用傳值返回, 傳值返回會導致至少1次拷貝構造(如果是一些舊一點的編譯器可能是兩次拷貝構造)。

????????

????????新的編譯器會對上面的構造進行優化(出現連續的構造函數時,編譯器會進行優化)

移動語義? ?

????????移動構造本質是將參數右值的資源竊取過來,占位已有,那么就不用做深拷貝了,所以它叫做移動構造,就是竊取別人的資源來構造自己。

?

????????這里to_string函數生成了一個str,這個str是左值,正常來說,to_string返回時,會再次調用構造函數生成一個臨時對象,但是這里編譯器做了優化(str被識別成將亡值,to_string返回時編譯器會將str識別成右值,進行返回),所以ret2的初始化操作省去了生成匿名對象,只有一個str的深拷貝構造和一個移動語義。

? ? ? ? 簡單來說,就是將str當成了右值進行ret2的初始化操作,所以只有一個移動語義

?

不僅僅有移動構造,還有移動賦值:

// 移動賦值
string& operator=(string&& s)
{cout << "string& operator=(string&& s) -- 移動語義" << endl;swap(s);return *this;
}
int main()
{bit::string ret1;ret1 = bit::to_string(1234);return 0;
}
// 運行結果:
// string(string&& s) -- 移動語義
// string& operator=(string&& s) -- 移動語義

????????這里運行后,我們看到調用了一次移動構造和一次移動賦值。

????????因為如果是用一個已經存在的對象接收,編譯器就沒辦法優化了。bit::to_string函數中會先用str生成構造生成一個臨時對象,但是 我們可以看到,編譯器很聰明的在這里把str識別成了右值,調用了移動構造。然后在把這個臨時 對象做為bit::to_string函數調用的返回值賦值給ret1,這里調用的移動賦值。

? ? ? ? 簡單來說,這里將str識別成右值,然后調用移動構造生成臨時對象進行賦值操作,所以這里有一個一次移動構造和一次移動賦值

?

Move()函數?

????????按照語法,右值引用只能引用右值,但右值引用一定不能引用左值嗎?因為:有些場景下,可能 真的需要用右值去引用左值實現移動語義。當需要用右值引用引用一個左值時,可以通過move 函數將左值轉化為右值。C++11中,std::move()函數位于 頭文件中,該函數名字具有迷惑性, 它并不搬移任何東西,唯一的功能就是將一個左值強制轉化為右值引用,然后實現移動語義。

? ?如下面例子:

? ? ?

int main()
{bit::string s1("hello world");// 這里s1是左值,調用的是拷貝構造bit::string s2(s1);// 這里我們把s1 move處理以后, 會被當成右值,調用移動構造// 但是這里要注意,一般是不要這樣用的,因為我們會發現s1的// 資源被轉移給了s3,s1被置空了。bit::string s3(std::move(s1));return 0;
}

需要注意的是:

? ? ? ? move函數將s1轉化為右值(返回一個s1的右值),但是s1本身還是左值。

還有下面這個例子:

?

?

(四)完美轉發

1.萬能引用(引用折疊)

?????????模板中的&&不代表右值引用,而是萬能引用,其既能接收左值又能接收右值。模板的萬能引用只是提供了能夠接收同時接收左值引用和右值引用的能力。

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }
// 模板中的&&不代表右值引用,而是萬能引用,其既能接收左值又能接收右值。
// 模板的萬能引用只是提供了能夠接收同時接收左值引用和右值引用的能力,
// 但是引用類型的唯一作用就是限制了接收的類型,后續使用中都退化成了左值,
// 我們希望能夠在傳遞過程中保持它的左值或者右值的屬性, 就需要用我們下面學習的完美轉發
template<typename T>
void PerfectForward(T&& t)
{Fun(t);
}
int main()
{PerfectForward(10); // 右值int a;PerfectForward(a); // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b); // const 左值PerfectForward(std::move(b)); // const 右值return 0;
}

運行結果:

可以看到不管是左值還是右值,引用后的對象都為左值(即 t 是左值);

?

如果我們保留原來的屬性呢??

? ? ? ? 因此有了std::forward 完美轉發在傳參的過程中保留對象原生類型屬性

2.完美轉發實際中的使用場景:

簡單舉個例子(該例子存在問題,只是幫助理解使用場景):

void Insert(Node* pos, T&& x);
void Insert(Node* pos, const T& x);template<class T>
void PushFront(T&& x)
{//Insert(_head->_next, x);Insert(_head->_next, std::forward<T>(x));
}int main()
{PushFront("2222");return 0;
}

這里我們調用PushFront(),即可以傳左值,也可以傳右值,因為有完美轉發,和forward()。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/75165.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/75165.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/75165.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

windows服務器切換到linux服務器踩坑點

單節點環境依賴性 單節點問題&#xff0c;影響業務可用性&#xff0c;windows影響后續自動化&#xff0c;健壯性的提升&#xff0c;需要進行linux化 每個服務至少是雙節點&#xff0c;防止單點故障&#xff0c;提升系統的可用性&#xff0c;健壯性。linux化后可以進行docker化…

美顏SDK兼容性挑戰:如何讓美顏濾鏡API適配iOS與安卓?

如何讓美顏濾鏡API同時適配iOS與Android&#xff0c;并確保性能流暢、效果一致&#xff0c;是開發者面臨的一大挑戰。今天&#xff0c;我將與大家一同深度剖析美顏SDK的跨平臺兼容性問題&#xff0c;并分享優化適配方案。 一、美顏SDK兼容性面臨的挑戰 1.1不同平臺的圖像處理框…

Vue3 表單

Vue3 表單 隨著前端技術的發展,Vue.js 作為一款流行的前端框架,不斷更新迭代,以適應更高效、更便捷的開發需求。Vue3 作為 Vue.js 的第三個主要版本,引入了許多新特性和改進,其中包括對表單處理機制的優化。本文將深入探討 Vue3 表單的使用方法、技巧以及注意事項。 1. …

筆記:代碼隨想錄算法訓練營day62:108.冗余連接、109.冗余連接II

學習資料&#xff1a;代碼隨想錄 108. 冗余連接 卡碼網題目鏈接&#xff08;ACM模式&#xff09; 判斷是否有環的依據為&#xff0c;利用并查集&#xff0c;isSame函數&#xff0c;判斷當下這條邊的兩個節點入集前是否為同根&#xff0c;如果是的話&#xff0c;該邊就是會構…

RK3588,V4l2 讀取Gmsl相機, Rga yuv422轉換rgb (mmap)

RK3588, 使用V4l2 讀取 gmsl 相機,獲得yuv422格式圖像, 使用 rga 轉換 rgb 圖像。減少cpu占用率. 內存管理方式采用 mmap… 查看相機信息 v4l2-ctl --all -d /dev/cam0 , 查看自己相機分辨率,輸出格式等信息,對應修改后續代碼測試… Driver Info:Driver name : rkcif…

Kubernetes》k8s》Containerd 、ctr 、cri、crictl

containerd ctr crictl ctr 是 containerd 的一個客戶端工具。 crictl 是 CRI 兼容的容器運行時命令行接口&#xff0c;可以使用它來檢查和調試 k8s 節點上的容器運行時和應用程序。 ctr -v 輸出的是 containerd 的版本&#xff0c; crictl -v 輸出的是當前 k8s 的版本&#x…

Vue 入門到實戰 十一 Vuex

目錄 11.1狀態管理與應用場景 1&#xff09;state 2&#xff09;Getters 3&#xff09;Mutations 4&#xff09;Actions 5&#xff09;Module 11.2Vuex的安裝與基本應用 11.3Vuex的核心概念 一句話解釋vuex&#xff1a;就是單獨成立一個組件&#xff0c;這個組件存儲共…

【YOLOv11】目標檢測任務-實操過程

目錄 一、torch環境安裝1.1 創建虛擬環境1.2 啟動虛擬環境1.3 安裝pytorch1.4 驗證cuda是否可用 二、yolo模型推理2.1 下載yolo模型2.2 創建模型推理文件2.3 推理結果保存路徑 三、labelimg數據標注3.1 安裝labelimg3.2 解決浮點數報錯3.3 labelimg UI界面介紹3.4 數據標注案例…

探索 Vue 中的多語言切換:<lang-radio /> 組件詳解!!!

探索 Vue 中的多語言切換&#xff1a;<lang-radio /> 組件詳解 &#x1f30d; 嗨&#xff0c;大家好&#xff01;&#x1f44b; 今天我們來聊聊如何在 Vue 項目中實現一個優雅的多語言切換功能——<lang-radio /> 組件。這是一個小而美的組件&#xff0c;出現在登…

grafana 配置頁面告警

添加告警規則 1.登錄grafana 點擊 Alerting > Alert rules 點擊 New alert rule 2.填寫告警規則名字 3.配置告警規則 選擇數據源為 Loki 單機 Builder 單機Label brower 單機 node_name 標簽&#xff0c;選擇一個主機&#xff0c;選好后單機 Show logs 這時候查詢語…

關于JVM和OS中的棧幀的區別和內存淺析

關于JVM和OS中的棧幀的區別和內存淺析 剛看了黑馬JVM中的棧幀的講解&#xff0c;感覺和自己理解的棧幀有一定出入&#xff0c;查詢資料研究了一下發現的確有天壤之別&#xff0c;可惜黑馬并沒有講。 故寫下這篇文章鞏固一下, OS的棧幀&#xff1a; ? OS的棧幀會在調用一個函…

Python FastApi(7):請求體

1 多個參數 1.1 混合使用 Path、Query 和請求體參數 首先&#xff0c;毫無疑問地&#xff0c;你可以隨意地混合使用 Path、Query 和請求體參數聲明&#xff0c;FastAPI 會知道該如何處理。你還可以通過將默認值設置為 None 來將請求體參數聲明為可選參數&#xff1a; from ty…

告別枯燥工作,走向自動化

嘿&#xff0c;小伙伴們&#xff01;今天給你們介紹兩款超實用的RPA辦公自動化軟件&#xff0c;用它們&#xff0c;再也不用像機器一樣做重復勞動啦&#xff0c;超省時間&#xff01; 工具名稱&#xff1a;影刀RPA&#xff08;類似產品&#xff0c;八爪魚 RPA&#xff0c;操作上…

一種C# Winform的UI處理

效果 圓角 陰影 突出按鈕 說明 這是一種另類的處理&#xff0c;不是多層窗口 也不是WPF 。這種方式的特點是比較簡單&#xff0c;例如圓角、陰影、按鈕等特別容易修改過。其實就是html css DirectXForm。 在VS中如下 圓角和陰影 然后編輯這個窗體的Html模板&#xff0c…

HarmonyOS-ArkUI Navigation (導航組件)-第一部分

導航組件主要實現頁面間以及組件內部的界面跳轉&#xff0c;支持在不同的組件間進行參數的傳遞&#xff0c;提供靈活的跳轉棧操作&#xff0c;從而便捷的實現對不同頁面的訪問和復用。 我們之前學習過Tabs組件&#xff0c;這個組件里面也有支持跳轉的方式&#xff0c;Navigati…

華為開源自研AI框架昇思MindSpore應用案例:基于MindSpore框架實現PWCNet光流估計

如果你對MindSpore感興趣&#xff0c;可以關注昇思MindSpore社區 1 環境準備 1.進入ModelArts官網 云平臺幫助用戶快速創建和部署模型&#xff0c;管理全周期AI工作流&#xff0c;選擇下面的云平臺以開始使用昇思MindSpore&#xff0c;可以在昇思教程中進入ModelArts官網 創建…

虛幻基礎:UI

文章目錄 控件藍圖可以裝載其他控件藍圖可以安裝其他藍圖接口 填充&#xff1a;相對于父組件填充水平框尺寸—填充—0.5&#xff1a;改變填充的尺寸填充—0.5&#xff1a;改變與父組件的距離 錨點&#xff1a;相對于父組件的控件坐標系原點&#xff0c;屏幕比例改變時&#xff…

監控平臺——SkyWalking部署

一、環境準備 先下載SkyWalking安裝包&#xff0c;需要注意的是SkyWalking 版本在10.X以上使用的nacos-client是2.X&#xff0c;如果安裝的Nacos版本是1.X就會存在兼容性的問題。由于本人使用的SpringBoot項目是2.7.X版本&#xff0c;安裝的Nacos版本只能是1.X版本的&#xff…

熱門索尼S-Log3電影感氛圍旅拍LUTS調色預設 Christian Mate Grab - Sony S-Log3 Cinematic LUTs

熱門索尼S-Log3電影感氛圍旅拍LUTS調色預設 Christian Mate Grab – Sony S-Log3 Cinematic LUTs 我們最好的 Film Look S-Log3 LUT 的集合&#xff0c;適用于索尼無反光鏡相機。無論您是在戶外、室內、風景還是旅行電影中拍攝&#xff0c;這些 LUT 都經過優化&#xff0c;可為…

自動化工作流工具的綜合對比與推薦

最近收到很多朋友私信我說&#xff1a;“刷短視頻的時候&#xff0c;總是刷到自動化工作流的工具&#xff0c;有好多直播間都在宣傳&#xff0c;不知道哪款工具好”。我花了點時間&#xff0c;做了一下測試&#xff0c;大家可以參考一下&#xff0c;以下內容&#xff1a; 以下…