【C++11】左值引用、右值引用、移動語義和完美轉發

🦄個人主頁:修修修也

🎏所屬專欄:C++

??操作環境:Visual Studio 2022


目錄

📌左值引用和右值引用

🎏左值和左值引用

🎏右值和右值引用

📌左值引用和右值引用比較?

🎏左值引用

🎏右值引用

📌左值引用和右值引用使用場景和意義

🎏左值引用使用場景和意義

🎏右值引用使用場景和意義

?🎏右值引用引用左值及其使用場景

📌完美轉發

🎏為什么需要完美轉發?

🎏如何實現完美轉發?

?🎏完整示例

結語


📌左值引用和右值引用

??????? 我們在一開始學習c++時就學習過引用的語法,當時我們將引用這一語法理解為給變量起別名。在c++11當中新增了右值引用語法特性,無論是左值引用還是右值引用,都是給對象起別名。注意,要摒棄一個誤區,不能簡單的認為在賦值號左邊的就叫左值,右邊的就叫右值,實際上左值右值的界定需要參照以下定義:


🎏左值和左值引用

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

??????? 左值引用就是給左值的引用,給左值取別名.如:

//左值引用
int a = 0;
int& r1 = a; //給a取別名為r1

🎏右值和右值引用

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

????????右值引用就是對右值的引用,給右值取別名.如:

//右值引用
int&& r5 = 10; //給10取別名為r5double x = 1.1, y = 2.2;
double&& r6 = x + y; //給表達式x+y取別名為r6

📌左值引用和右值引用比較?

🎏左值引用

  1. 左值引用只能引用左值,不能引用右值
  2. 但是const左值引用既可以引用左值,也可以引用右值
/左值引用引用右值
double x = 2.2;
double y = 3.3;
const int& r2 = 10;
const double& r3 = x + y;//這里x和y都是左值,但是x+y表達式返回的結果5是一個臨時變量是右值

🎏右值引用

  1. 右值引用只能引用右值,不能引用左值.
  2. 但是特殊情況下右值引用可以引用move以后的左值.
//右值引用引用左值
int a = 10;
int&& r7 = move(a);

??????? 也就是說,正常情況下左值只能引用左值, 右值只能引用右值, 但是const左值可以引用右值,右值可以引用move后的左值。


📌左值引用和右值引用使用場景和意義

🎏左值引用使用場景和意義

左值引用使用場景:

  1. 做參數
    void swap(int& a,int&b) //左值引用可以直接修改原對象,減少參數傳遞時的拷貝
    {int tmp = a;a = b;b = tmp;
    }int main()
    {int x = 2;int y = 3;swap(x,y);return 0;
    }
    
  2. 做返回值
    //左值引用可以直接修改返回值,同時減少了函數傳值返回的拷貝
    int& get(size_t pos)
    {return data[pos];
    }

左值引用意義: 減少拷貝,并可以直接修改原對象

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

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


🎏右值引用使用場景和意義

??????? 通過上面我們對左值引用使用場景和意義的分析,我們得知了左值引用的短板。因此C++的大佬們就引入了右值引用和移動語義來解決這個問題:移動語義包括移動構造和移動賦值,我們先來看移動構造:

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

??????? 而移動賦值也是將賦值運算符右邊的右值資源竊取過來,占為己有,也就不用再做深拷貝了:

??????? 基于上面的概念,實現的string類移動構造和移動賦值函數如下:

//移動構造
string(string&& s):_str(nullptr), _size(0), _capacity(0)
{swap(s);
}//移動賦值
string& operator=(string&& s)
{swap(s);return *this;
}

?🎏右值引用引用左值及其使用場景

??????? 有些場景下,我們可能需要用右值去引用左值實現移動語義。當需要用右值引用引用一個左值時,可以通過move函數將左值轉化為右值。

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


📌完美轉發

????????完美轉發(Perfect Forwarding)?是 C++11 引入的核心特性之一,用于在泛型編程中精確傳遞參數的左值/右值屬性,避免不必要的拷貝或類型損失。它結合了?右值引用萬能引用(Universal Reference)?和?std::forward?實現。


🎏為什么需要完美轉發?

????????假設有一個泛型函數?wrapper,需要將參數轉發給另一個函數?target

template<typename T>
void wrapper(T arg){target(arg);  // 直接傳遞參數
}

問題:

  1. 值類別丟失:無論?arg?是左值還是右值,target(arg)?接收的始終是左值(因為右值引用本身是左值, 如果右值引用本身是右值那么就沒法移動語義了)所以左值引用和右值引用傳遞到下層都變成了左值引用。

  2. 拷貝開銷:若?arg?是臨時對象(右值),無法觸發移動語義,可能導致深拷貝。

???????? 右值引用默認是左值,我們才能基于此實現移動語義:

??????? 但是如果不支持完美轉發的話,右值引用無法保持右值屬性,那么我們遇到嵌套容器深拷貝的情況就沒法用移動語義:


🎏如何實現完美轉發?

1. 萬能引用(Universal?Reference)

  • 語法:模板參數中使用?T&&,且?T?需要被推導(如函數模板或?auto)。

  • 特性:可以綁定到左值或右值,保留參數的原始類型信息。

  • 如果實參是左值,他就是左值引用(引用折疊)

  • 如果實參是右值,他就是右值引用

template<typename T>
void wrapper(T&& arg) {  // arg 是萬能引用// 模板中的&&不代表右值引用,而是萬能引用,其既能接收左值又能接收右值。// 模板的萬能引用只是提供了能夠接收同時接收左值引用和右值引用的能力,// 但是引用類型的唯一作用就是限制了接收的類型,后續使用中都退化成了左值,// 我們希望能夠在傳遞過程中保持它的左值或者右值的屬性, 就需要用我們下面學習的完美轉發
}

2.?std::forward<T>

  • 作用:根據?T?的原始類型(左值或右值),將參數有條件地轉換回原始類型

  • 本質:若?T?是左值引用,返回左值;否則返回右值引用(觸發移動語義)。

?🎏完整示例

#include <iostream>
#include <utility>  // std::forward// 目標函數
void target(int& x)  { std::cout << "左值: " << x << std::endl; }
void target(int&& x) { std::cout << "右值: " << x << std::endl; }// 完美轉發的包裝函數
template<typename T>
void wrapper(T&& arg) 
{target(std::forward<T>(arg));  // 關鍵:保留參數的原始類型
}int main() 
{int a = 10;wrapper(a);       // 傳遞左值 → 調用 target(int&)wrapper(20);      // 傳遞右值 → 調用 target(int&&)wrapper(std::move(a)); // 顯式轉為右值 → 調用 target(int&&)return 0;
}

結語

希望這篇關于 C++11之左值引用,右值引用和移動語義 的博客能對大家有所幫助,歡迎大佬們留言或私信與我交流.

學海漫浩浩,我亦苦作舟!關注我,大家一起學習,一起進步!

?相關文章推薦

【C++】STL標準模板庫容器set

【C++】模擬實現二叉搜索(排序)樹

【數據結構】C語言實現鏈式二叉樹(附完整運行代碼)

【數據結構】什么是二叉搜索(排序)樹?

【C++】模擬實現priority_queue(優先級隊列)

【C++】模擬實現queue

【C++】模擬實現stack

【C++】模擬實現list

【C++】模擬實現vector

【C++】標準庫類型vector

【C++】模擬實現string類

【C++】標準庫類型string

【C++】構建第一個C++類:Date類

【C++】類的六大默認成員函數及其特性(萬字詳解)

【C++】什么是類與對象?


?

強烈呼吁大家在寫CSDN的時候把Ctrl+z給禁用掉,否則有一定幾率導致您的創作窗口一秒穿越到n小時前。且根本沒有一點辦法恢復。這篇文章就是血的教訓...🥲

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

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

相關文章

麒麟系列Linux發行版探秘

以下內容摘自《銀河麒麟操作系統進階應用》一書。 銀河麒麟操作系統&#xff08;Kylin&#xff09; 銀河麒麟&#xff08;Kylin&#xff09;操作系統是中國自主研發的一款基于Linux內核的操作系統。它的發展歷程可以追溯到2002年&#xff0c;最初由國防科技大學主導研發&…

【機密計算頂會解讀】11:ACAI——使用 Arm 機密計算架構保護加速器執行

導讀&#xff1a;本文介紹ACAI&#xff0c;其構建一個基于CCA的解決方案&#xff0c;使得機密虛擬機能夠安全地使用加速器&#xff0c;同時保持與現有應用程序的兼容性和安全性&#xff0c;能夠實現對加速器的安全訪問。 原文鏈接&#xff1a;ACAI: Protecting Accelerator Ex…

第一天 UnityShader的結構

Shader初學者的學習筆記 第一天 Unity Shader的結構 文章目錄 Shader初學者的學習筆記前言一、Unity Shader結構二、Unity Shader結構解析① Properties② Tags③ RenderSetup(可選狀態)④ Name⑤ [Tags]⑥ [RenderSetup]⑦ 頂點著色器和片元著色器的代碼 (Unity最聰明的孩子)…

VL開源模型實現文本生成圖片

一、 基礎知識 根據描述生成圖片的視覺-語言模型&#xff08;Vision-Language Models, VL 模型&#xff09;是近年來多模態生成領域的熱點研究方向。這些模型能夠根據自然語言描述生成高質量的圖像&#xff0c;廣泛應用于藝術創作、設計輔助、虛擬場景構建等領域。 1 根據描述…

【Java SE】抽象類/方法、模板設計模式

目錄 1.抽象類/方法 1.1 基本介紹 1.2 語法格式 1.3 使用細節 2. 模板設計模式&#xff08;抽象類使用場景&#xff09; 2.1 基本介紹 2.2 具體例子 1.抽象類/方法 1.1 基本介紹 ① 當父類的某些方法&#xff0c;需要聲明&#xff0c;但是又不確定如何實現時&#xff…

【人工智能】LM Studio 的 GPU 加速:釋放大模型推理潛能的極致優化

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 隨著大語言模型(LLM)的廣泛應用,其推理效率成為限制性能的關鍵瓶頸。LM Studio 作為一個輕量級機器學習框架,通過 GPU 加速顯著提升了大…

深度學習:從零開始的DeepSeek-R1-Distill有監督微調訓練實戰(SFT)

原文鏈接&#xff1a;從零開始的DeepSeek微調訓練實戰&#xff08;SFT&#xff09; 微調參考示例&#xff1a;由unsloth官方提供https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen2.5_(7B)-Alpaca.ipynbhttps://colab.research.google.com/git…

流暢如絲:利用requestAnimationFrame優化你的Web動畫體驗

requestAnimationFrame 是前端開發中用于優化動畫性能的 API。它允許瀏覽器在下一次重繪之前執行指定的回調函數&#xff0c;通常用于實現平滑的動畫效果。 1.作用 優化性能&#xff1a;requestAnimationFrame 會根據瀏覽器的刷新率&#xff08;通常是 60Hz&#xff0c;即每秒…

【pytest框架源碼分析五】pytest插件的注冊流程

前文介紹到pytest整體是運用插件來實現其運行流程的。這里仔細介紹下具體過程。 首先進入main方法 def main(args: list[str] | os.PathLike[str] | None None,plugins: Sequence[str | _PluggyPlugin] | None None, ) -> int | ExitCode:"""Perform an i…

IoTDB日志提示Too many open files

問題 時序數據庫 IoTDB 1.3.3 版本 IoTDB 執行查詢操作失敗&#xff0c;日志打印提示 Too many open files。通過命令查看打開文件數&#xff0c;結果如下&#xff1a; [root0002 DataReceiver]# lsof|grep 28347|wc -l DataNode 55444 [root0002 DataReceiver]# lsof|g…

prometheus 添加alertmanager添加dingtalk機器人告警

1、dingtalk創建機器人,目前我們采用加白名單的方式校驗 2、定位到如下圖 test結果如下

C 語 言 --- 操 作 符 2

C 語 言 --- 操 作 符 2 移 位 操 作 符定 義原 碼 補 碼 和 反 碼左 移&#xff08;<<&#xff09;右 移&#xff08;>>&#xff09;算 術 右 移邏 輯 右 移 按 位 與、按 位 或、和 按 位 異 或按 位 與按 位 或按 位 異 或 邏 輯 反 操 作負 值 操 作按 位 取 反…

基于Spring Boot的公司資產網站的設計與實現(LW+源碼+講解)

專注于大學生項目實戰開發,講解,畢業答疑輔導&#xff0c;歡迎高校老師/同行前輩交流合作?。 技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;…

零碳工廠能源管理系統的核心技術與應用實踐

零碳工廠能源管理系統是一種高效的解決方案&#xff0c;旨在優化能源使用并減少碳排放&#xff0c;以幫助工廠實現低碳或零碳的生產目標。以下是該系統的詳細構成和功能&#xff1a; 1. 核心組件 傳感器和監測設備&#xff1a;用于實時監測工廠內的能源使用情況&#xff0c;包…

美攝接入DeepSeek等大模型,用多模態融合重構視頻創作新邊界!

今年以來&#xff0c;DeepSeek憑借其強大的深度推理分析能力&#xff0c;在AI領域掀起新的熱潮。美攝科技快速響應市場需求&#xff0c;迅速接入以DeepSeek、通義千問、商湯、文心一言為代表的大模型&#xff0c;為企業視頻創作生產帶來全新體驗。 傳統視頻創作面臨著同質化、…

JAVA————十五萬字匯總

JAVA語言概述 JAVA語句結構 JAVA面向對象程序設計&#xff08;一&#xff09; JAVA面向對象程序設計&#xff08;二&#xff09; JAVA面向對象程序設計&#xff08;三&#xff09;工具類的實現 JAVA面向對象程序設計&#xff08;四&#xff09;錄入異常處理 JAVA圖形用戶界面設…

力扣熱題100(方便自己復習,自用)

力扣熱題100 1. 兩數之和 - 力扣&#xff08;LeetCode&#xff09; 查找兩數之和是不是等于target也就是我們找到一個數之后&#xff0c;用target將其減掉&#xff0c;再尋找應當對應的元素是什么每找到一個數&#xff0c;我們就將其放在集合中&#xff0c;因為集合中可以去重…

【yolo】yolo訓練報錯,以及解決方案

背景&#xff1a; 剛剛&#xff0c;寫了《【yolo】yolo推理報錯&#xff0c;以及解決方案》&#xff0c;馬上訓練就遇到類似的報錯。 我對我標注的圖像進行了300輪的訓練&#xff0c;但是訓練完300輪后&#xff0c;報錯了。。。 報錯信息 300 epochs completed in 0.085 hou…

vscode/cursor中python運行路徑設置 模塊導入問題

vscode/cursor中python運行路徑設置 ## 文件路徑設置 問題描述 pycharm的項目用cursor運行&#xff0c;出現目錄找不到 后來利用 os.getcwd()&#xff0c;經過打印調試發現是IDE的本身配置問題 pycharm中&#xff0c;os.getcwd()默認打開當前腳本所在目錄 vscode/cursor中…

理解線性動力學中的模態疊加法

線性動力學中的模態疊加方法 模態疊加法是線性動力學中一種有價值的工具&#xff0c;可以有效地確定頻域或時域中的系統響應。對于某些類型的線性動力學分析&#xff0c;有必要使用此方法&#xff0c;因此了解該過程對于獲得準確的結果至關重要。在本博客中&#xff0c;我們將…