最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++?左值、右值、左值引用、右值引用的用途及區(qū)別

 更新時間:2025年09月20日 09:07:11   作者:xclic  
本文給大家介紹了C++左值、右值、左值引用、右值引用用途及區(qū)別,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧

1、左值與右值

左值和右值是表達式的屬性,核心區(qū)別在于:能否取地址、是否有持久的存儲

1.1 左值:有名字、能取地址、可被修改(通常)

左值是 “可以放在賦值號左邊” 的表達式(但并非絕對,如 const 左值不能被修改),它有明確的內(nèi)存地址,生命周期較長(如變量)。

int a = 10; // a 是左值(有名字、能取地址)
int* p = &a; // 合法:左值可以取地址
const int b = 20; // b 是 const 左值(有名字、能取地址,但不能修改)
// b = 30; // 錯誤:const 左值不可修改
int arr[5]; 
arr[0] = 1; // arr[0] 是左值(數(shù)組元素有地址)

1.2 右值:無名字、不能取地址、臨時存在

右值是 “只能放在賦值號右邊” 的表達式,通常是臨時結(jié)果(如字面量、表達式計算結(jié)果),沒有持久的內(nèi)存地址,生命周期短暫(表達式結(jié)束后銷毀)。

int a = 10;
int b = 20;
// 以下都是右值
100; // 字面量(無名字,不能取地址)
a + b; // 表達式結(jié)果(臨時值,無名字)
func(); // 函數(shù)返回值(非引用類型時,是臨時值)

關(guān)鍵特征

  • 右值不能被取地址:&(a + b) 會編譯報錯(無法對臨時值取地址)。
  • 右值是 “消耗品”:使用后就會銷毀(除非被保存到左值中)。

右值的細分

C++11 后,右值又分為兩種,但日常使用中無需嚴格區(qū)分,知道它們都是右值即可:

  • 純右值(Prvalue):字面量(如 10)、表達式結(jié)果(如 a + b)、非引用返回的函數(shù)結(jié)果。
  • 將亡值(Xvalue):通過 std::move 轉(zhuǎn)換后的左值(本質(zhì)是 “即將被銷毀的左值”,可被移動)。

2、左值引用:綁定左值的 “別名”

左值引用是最常用的引用類型,用 & 表示,只能綁定左值,本質(zhì)是給左值起一個 “別名”,操作引用等價于操作原對象。

2.1 基本用法

int a = 10;
int& ref_a = a; // 正確:左值引用綁定左值(ref_a 是 a 的別名)
ref_a = 20; // 等價于 a = 20,a 現(xiàn)在是 20

2.2 左值引用的限制

不能綁定右值

// int& ref = 10; // 錯誤:左值引用不能綁定右值(10 是右值)

const 左值引用是特例:可以綁定右值(臨時延長右值的生命周期):

const int& ref = 10; // 正確:const 左值引用可綁定右值
// 原理:編譯器會生成臨時變量存儲 10,ref 綁定這個臨時變量(臨時變量生命周期被延長至 ref 相同)

2.3 左值引用的用途

避免函數(shù)傳參時的拷貝(如傳遞大對象 vector):

void func(const vector<int>& v) { ... } // 傳引用,無拷貝

允許函數(shù)修改外部變量(非 const 引用):

void increment(int& x) { x++; }
int a = 5;
increment(a); // a 變?yōu)?6

3、右值引用:綁定右值的 “專屬引用”

右值引用是 C++11 新增的引用類型,用 && 表示,專門綁定右值,目的是 “利用右值的臨時特性” 實現(xiàn)移動語義(避免不必要的拷貝)。

3.1 基本用法

int&& ref1 = 10; // 正確:右值引用綁定純右值(10 是右值)
int a = 10, b = 20;
int&& ref2 = a + b; // 正確:右值引用綁定表達式結(jié)果(右值)

3.2 右值引用的限制

不能直接綁定左值:

int a = 10;
// int&& ref = a; // 錯誤:右值引用不能直接綁定左值

但可以通過 std::move 將左值 “強制轉(zhuǎn)換” 為右值引用(本質(zhì)是告訴編譯器:“這個左值可以被當(dāng)作右值處理,資源可以被轉(zhuǎn)移”)

int a = 10;
int&& ref = std::move(a); // 正確:std::move 將 a 轉(zhuǎn)為右值引用

注意std::move 不會移動任何數(shù)據(jù),只是 “標記” 左值為 “可被移動” 的右值,本身是編譯期操作,無運行時開銷。

3.3 右值引用的核心用途:移動語義

右值引用的最大價值是實現(xiàn)移動語義—— 對于臨時對象(右值),不再進行昂貴的拷貝,而是直接 “竊取” 其資源(如內(nèi)存),大幅提升性能。

移動構(gòu)造函數(shù)

class MyString {
private:
    char* data; // 存儲字符串的動態(tài)內(nèi)存
public:
    // 普通構(gòu)造函數(shù)
    MyString(const char* str) {
        size_t len = strlen(str);
        data = new char[len + 1];
        strcpy(data, str);
        cout << "構(gòu)造函數(shù):分配內(nèi)存" << endl;
    }
    // 拷貝構(gòu)造函數(shù)(左值引用參數(shù),深拷貝)
    MyString(const MyString& other) {
        size_t len = strlen(other.data);
        data = new char[len + 1];
        strcpy(data, other.data);
        cout << "拷貝構(gòu)造:深拷貝(性能差)" << endl;
    }
    // 移動構(gòu)造函數(shù)(右值引用參數(shù),直接竊取資源)
    MyString(MyString&& other) noexcept {
        data = other.data; // 直接接管 other 的內(nèi)存
        other.data = nullptr; // other 放棄資源(避免析構(gòu)時重復(fù)釋放)
        cout << "移動構(gòu)造:竊取資源(性能好)" << endl;
    }
    ~MyString() {
        if (data) delete[] data;
        cout << "析構(gòu)函數(shù):釋放內(nèi)存" << endl;
    }
};
int main() {
    MyString s1("hello"); // 調(diào)用普通構(gòu)造
    MyString s2 = s1; // 調(diào)用拷貝構(gòu)造(s1 是左值,必須深拷貝)
    MyString s3 = MyString("world"); // 調(diào)用移動構(gòu)造(臨時對象是右值,直接竊取資源)
    MyString s4 = std::move(s1); // 調(diào)用移動構(gòu)造(s1 被轉(zhuǎn)為右值,資源被 s4 竊取)
    return 0;
}

輸出

構(gòu)造函數(shù):分配內(nèi)存
拷貝構(gòu)造:深拷貝(性能差)
構(gòu)造函數(shù):分配內(nèi)存
移動構(gòu)造:竊取資源(性能好)
移動構(gòu)造:竊取資源(性能好)
析構(gòu)函數(shù):釋放內(nèi)存
析構(gòu)函數(shù):釋放內(nèi)存
析構(gòu)函數(shù):釋放內(nèi)存

關(guān)鍵:移動構(gòu)造函數(shù)通過右值引用參數(shù),識別出臨時對象(或被 std::move 標記的左值),直接接管其資源,避免了拷貝開銷(對于大對象,性能提升顯著)。

4、萬能引用與完美轉(zhuǎn)發(fā)

在模板中,還有一種特殊的 “萬能引用”,它能同時接受左值和右值,并通過 “完美轉(zhuǎn)發(fā)” 保持原表達式的屬性(左值還是右值)。

4.1 萬能引用:能接受左值和右值的引用

萬能引用僅出現(xiàn)在模板參數(shù)中,形式為 T&&,其類型會根據(jù)傳入的參數(shù)自動推導(dǎo):

  • 若傳入左值,T&& 會被推導(dǎo)為 “左值引用”(T&);
  • 若傳入右值,T&& 會被推導(dǎo)為 “右值引用”(T&&)。
template <typename T>
void func(T&& t) { // 萬能引用(僅模板中 T&& 才是萬能引用)
    // 根據(jù)傳入的參數(shù),t 可能是左值引用或右值引用
}
int main() {
    int a = 10;
    func(a); // 傳入左值,T 推導(dǎo)為 int&,func 實際為 void func(int& t)
    func(20); // 傳入右值,T 推導(dǎo)為 int,func 實際為 void func(int&& t)
    return 0;
}

注意:萬能引用≠右值引用。只有模板中 T&& 且 T 是模板參數(shù)時,才是萬能引用;其他場景的 && 都是右值引用(如 void func(int&& t) 是右值引用)。

4.2 完美轉(zhuǎn)發(fā):保持原參數(shù)的左值 / 右值屬性

完美轉(zhuǎn)發(fā)是指在函數(shù)模板中,將參數(shù)通過萬能引用接收后,原封不動地轉(zhuǎn)發(fā)給其他函數(shù)(保持其左值 / 右值屬性)。需要配合 std::forward 實現(xiàn)。

為什么需要完美轉(zhuǎn)發(fā)?如果直接傳遞萬能引用參數(shù),會丟失原屬性(因為引用本身是左值):

void target(int& x) { cout << "左值版本" << endl; }
void target(int&& x) { cout << "右值版本" << endl; }
template <typename T>
void func(T&& t) {
    target(t); // 錯誤:t 是引用(有名字),被當(dāng)作左值處理,始終調(diào)用 target(int&)
}
int main() {
    int a = 10;
    func(a); // 傳入左值,期望調(diào)用 target(int&) → 實際正確
    func(20); // 傳入右值,期望調(diào)用 target(int&&) → 實際錯誤(調(diào)用了左值版本)
    return 0;
}

用 std::forward 實現(xiàn)完美轉(zhuǎn)發(fā):

template <typename T>
void func(T&& t) {
    target(std::forward<T>(t)); // 完美轉(zhuǎn)發(fā):保持 t 的原始屬性
}
int main() {
    int a = 10;
    func(a); // 傳入左值 → 轉(zhuǎn)發(fā)為左值 → 調(diào)用 target(int&)
    func(20); // 傳入右值 → 轉(zhuǎn)發(fā)為右值 → 調(diào)用 target(int&&)
    return 0;
}

原理std::forward<T>(t) 會根據(jù) T 的類型(左值引用或右值引用),將 t 還原為原始的左值或右值屬性。

5、常見問題

  • 左值和右值有什么區(qū)別?
    • 左值:有標識符,可以取地址,生命周期較長,可以出現(xiàn)在賦值左邊
    • 右值:匿名臨時對象,不能取地址,生命周期短,只能出現(xiàn)在賦值右邊
  • 左值引用和右值引用有什么區(qū)別?
    • 左值引用 (T&):只能綁定到左值,用于創(chuàng)建別名
    • 右值引用 (T&&):只能綁定到右值,用于實現(xiàn)移動語義和完美轉(zhuǎn)發(fā)
  • std::move 做了什么?它真的移動數(shù)據(jù)嗎?
  • std::move 只是進行類型轉(zhuǎn)換,將左值轉(zhuǎn)換為右值引用
  • 它本身不移動任何數(shù)據(jù),只是標記對象為"可移動的"
  • 實際的移動操作在移動構(gòu)造函數(shù)移動賦值運算符中完成
  • 使用 std::move 后,原始對象會怎樣?
  • 對象處于"有效但未指定狀態(tài)"
  • 不應(yīng)該再使用該對象,除非重新賦值
  • 析構(gòu)函數(shù)仍然需要正常工作
  • 移動語義有什么優(yōu)勢?
    • 性能提升:避免不必要的深拷貝,特別是對于管理資源的類
    • 資源轉(zhuǎn)移:允許高效地轉(zhuǎn)移資源所有權(quán)
    • 支持不可拷貝對象:可以移動但不能拷貝的對象
  • std::forward 和 std::move 有什么區(qū)別?
    • std::move:無條件將左值轉(zhuǎn)為右值引用
    • std::forward:有條件地轉(zhuǎn)換,保持參數(shù)的原始值類別
  • 如何實現(xiàn)一個支持移動語義的字符串類?
class MyString {
private:
    char* data;
    size_t size;
public:
    // 移動構(gòu)造函數(shù)
    MyString(MyString&& other) noexcept 
        : data(other.data), size(other.size) {
        other.data = nullptr;
        other.size = 0;
    }
    // 移動賦值運算符
    MyString& operator=(MyString&& other) noexcept {
        if (this != &other) {
            delete[] data;
            data = other.data;
            size = other.size;
            other.data = nullptr;
            other.size = 0;
        }
        return *this;
    }
    // 析構(gòu)函數(shù)
    ~MyString() {
        delete[] data;
    }
    // 禁用拷貝(可選)
    MyString(const MyString&) = delete;
    MyString& operator=(const MyString&) = delete;
};

什么情況下應(yīng)該使用完美轉(zhuǎn)發(fā)?

應(yīng)該在包裝函數(shù)、工廠函數(shù)、構(gòu)造函數(shù)轉(zhuǎn)發(fā)等場景中使用完美轉(zhuǎn)發(fā),以保持參數(shù)的原始值類別。

// 包裝器函數(shù)
template<typename Func, typename... Args>
auto wrapper(Func&& func, Args&&... args) {
    return std::forward<Func>(func)(std::forward<Args>(args)...);
}
// 工廠函數(shù)
template<typename T, typename... Args>
T create(Args&&... args) {
    return T(std::forward<Args>(args)...);
}

右值引用本身是左值還是右值?

右值引用本身是左值。因為右值引用有名字、可以取地址(符合左值的特征)。

int&& ref = 10; // ref 是右值引用,但自身是左值
int& ref2 = ref; // 正確:ref 是左值,可綁定到左值引用

這也是為什么在轉(zhuǎn)發(fā)右值引用時,需要用 std::forward 才能還原其右值屬性。

const 左值引用為什么能綁定右值?

為了靈活性。const 左值引用設(shè)計的初衷之一是 “安全地引用臨時對象”,編譯器會為右值創(chuàng)建一個臨時變量,const 左值引用綁定這個臨時變量,并延長其生命周期(與引用同生命周期)。

用途:允許函數(shù)接受右值作為參數(shù)(如 void print(const string& s) 可接收字符串字面量 print("hello")),同時保證不修改原對象(const 約束)。

什么時候該用移動語義?

函數(shù)返回局部對象時

傳遞臨時對象給函數(shù)時

容器重新分配內(nèi)存時

資源管理類(如智能指針)傳遞所有權(quán)時

什么是返回值優(yōu)化(RVO)?與移動語義的關(guān)系?

返回值優(yōu)化(RVO)是編譯器優(yōu)化技術(shù),允許直接在調(diào)用者內(nèi)存中構(gòu)造返回對象,避免拷貝。與移動語義的關(guān)系:

RVO優(yōu)先級高于移動語義

當(dāng)RVO不可用時,編譯器使用移動語義

C++17強制要求部分場景的RVO(稱為"guaranteed copy elision")

6、總結(jié)

左值/右值
├── 左值 (lvalue):有名字、可尋址
├── 右值 (rvalue):臨時對象、字面量
│   ├── 純右值 (prvalue)
│   └── 將亡值 (xvalue)
│
引用類型
├── 左值引用 (&):綁定左值
├── 右值引用 (&&):綁定右值
└── 通用引用 (T&&):模板推導(dǎo)
    └── 完美轉(zhuǎn)發(fā) (std::forward)

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

相關(guān)文章

  • EasyX繪制透明背景圖的方法詳解

    EasyX繪制透明背景圖的方法詳解

    這篇文章主要為大家詳細介紹了EasyX繪制透明背景圖的方法,文中的示例代碼講解詳細,對我們深入了解EasyX有一定的幫助,需要的可以參考一下
    2023-01-01
  • C++使用nlohmann/json庫解析和處理JSON數(shù)據(jù)的操作指南

    C++使用nlohmann/json庫解析和處理JSON數(shù)據(jù)的操作指南

    本章節(jié)介紹了如何在C++項目中使用nlohmann/json庫來解析和處理JSON數(shù)據(jù),我們將展示如何安裝和配置該庫,并通過封裝的JsonHandler類來簡化JSON數(shù)據(jù)的操作過程,需要的朋友可以參考下
    2025-10-10
  • C++實現(xiàn)std::set的示例項目

    C++實現(xiàn)std::set的示例項目

    std::set是C++標準庫中的關(guān)聯(lián)容器,提供有序唯一元素集合,本文就來介紹一下std::set的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2025-02-02
  • C++中const應(yīng)放在類型前還是后

    C++中const應(yīng)放在類型前還是后

    之前遇到小伙伴問C++中const加在類型名前和變量名前的區(qū)別,今天給大家簡單分析下。
    2016-05-05
  • C++非遞歸隊列實現(xiàn)二叉樹的廣度優(yōu)先遍歷

    C++非遞歸隊列實現(xiàn)二叉樹的廣度優(yōu)先遍歷

    這篇文章主要介紹了C++非遞歸隊列實現(xiàn)二叉樹的廣度優(yōu)先遍歷,實例分析了遍歷二叉樹相關(guān)算法技巧,并附帶了兩個相關(guān)算法實例,需要的朋友可以參考下
    2015-07-07
  • C++實現(xiàn)LeetCode(50.求x的n次方)

    C++實現(xiàn)LeetCode(50.求x的n次方)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(50.求x的n次方),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++ UML類圖的使用解讀

    C++ UML類圖的使用解讀

    這篇文章主要介紹了C++ UML類圖的使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • C經(jīng)典算法之二分查找法

    C經(jīng)典算法之二分查找法

    這篇文章主要介紹了C經(jīng)典算法之二分查找法的相關(guān)資料,這里提供兩種方法幫助大家實現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-10-10
  • VScode搭建OpenCV環(huán)境的詳細步驟

    VScode搭建OpenCV環(huán)境的詳細步驟

    用vscode來寫opencv代碼需要自己編譯OpenCV,主要用到MinGW-w64和CMake工具。接下來通過本文給大家介紹VScode搭建OpenCV環(huán)境的相關(guān)知識,需要的朋友可以參考下
    2021-11-11
  • C語言計算代碼執(zhí)行所耗CPU時鐘周期

    C語言計算代碼執(zhí)行所耗CPU時鐘周期

    本文給大家介紹的是使用C語言來計算代碼執(zhí)行所耗CPU時鐘周期的代碼,非常的簡單實用,不過要依托于sync,有需要的小伙伴自己參考下吧。
    2015-03-03

最新評論

法库县| 台南市| 乐陵市| 定安县| 汶川县| 西青区| 汶川县| 阜平县| 自治县| 洪泽县| 西和县| 东乌珠穆沁旗| 舞钢市| 林口县| 五河县| 仁布县| 尚义县| 陈巴尔虎旗| 泰州市| 剑阁县| 沙田区| 大连市| 德惠市| 高阳县| 洛川县| 贡觉县| 谷城县| 阿尔山市| 达拉特旗| 承德县| 潞西市| 洛阳市| 巴楚县| 无为县| 霍城县| 淮滨县| 安吉县| 鄯善县| 海伦市| 澄城县| 亳州市|