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

C++?11新特性之右值引用使用案例與應(yīng)用場(chǎng)景

 更新時(shí)間:2024年01月30日 11:28:56   作者:hope_wisdom  
右值引用和move語(yǔ)義是C++ 11中重要的特性之一,可以提高程序的效率和性能,右值引用是一種新的引用類型,下面這篇文章主要給大家介紹了關(guān)于C++?11新特性之右值引用使用案例與應(yīng)用場(chǎng)景的相關(guān)資料,需要的朋友可以參考下

概述

C++ 11中引入了一項(xiàng)關(guān)鍵特性——右值引用,極大地增強(qiáng)了C++在資源管理、性能優(yōu)化和表達(dá)力方面的能力。通過(guò)理解并合理運(yùn)用右值引用,我們可以編寫出更高效、更簡(jiǎn)潔且不易出錯(cuò)的代碼。本文將深入探討右值引用的概念、工作原理及其在C++編程實(shí)踐中的應(yīng)用場(chǎng)景。

右值引用是C++中的一種特殊引用類型,它只能綁定到臨時(shí)對(duì)象或即將銷毀的對(duì)象上,也就是那些沒(méi)有命名且不再需要的對(duì)象。語(yǔ)法上,右值引用以&&表示,可參考下面的示例代碼。

// 右值引用,綁定到字面量整數(shù)
int&& nData = 42;

工作原理

理解右值引用是學(xué)習(xí)“移動(dòng)語(yǔ)義”的基礎(chǔ),而要理解右值引用,就必須先區(qū)分左值與右值。

對(duì)左值和右值的一個(gè)最常見的誤解是:等號(hào)左邊的就是左值,等號(hào)右邊的就是右值。左值和右值都是針對(duì)表達(dá)式而言的,左值是指表達(dá)式結(jié)束后依然存在的持久對(duì)象,右值是指表達(dá)式結(jié)束時(shí)就不再存在的臨時(shí)對(duì)象。一個(gè)區(qū)分左值與右值的便捷方法是:看能不能對(duì)表達(dá)式取地址,如果能,則為左值,否則為右值。下面我們結(jié)合一些實(shí)際例子來(lái)進(jìn)行說(shuō)明。

int a = 100;
int b = 200;
int *pFlag = &a;
vector<int> vctTemp;
vctTemp.push_back(66);
string str1 = "Hello ";
string str2 = "World";
const int &m = 99;

請(qǐng)問(wèn):a、b、a+b、a++、++a、pFlag、*pFlag、vctTemp[0]、100、string("CSDN")、str1、str1+str2、m分別是左值還是右值?

1、a和b都是持久對(duì)象(可以對(duì)其取地址),是左值。

2、a+b是臨時(shí)對(duì)象(不可以對(duì)其取地址),是右值。

3、a++是先取出持久對(duì)象a的一份拷貝,再使持久對(duì)象a的值加1,最后返回那份拷貝,而那份拷貝是臨時(shí)對(duì)象(不可以對(duì)其取地址),故其是右值。

4、++a則是使持久對(duì)象a的值加1,并返回那個(gè)持久對(duì)象a本身(可以對(duì)其取地址),故其是左值。

5、pFlag和*pFlag都是持久對(duì)象(可以對(duì)其取地址),是左值。

6、vctTemp[0]調(diào)用了重載的[]操作符,而[]操作符返回的是一個(gè)int &,為持久對(duì)象(可以對(duì)其取地址),是左值。

7、100和string("CSDN")是臨時(shí)對(duì)象(不可以對(duì)其取地址),是右值。

8、str1是持久對(duì)象(可以對(duì)其取地址),是左值。

9、str1+str2是調(diào)用了+操作符,而+操作符返回的是一個(gè)string(不可以對(duì)其取地址),故其為右值。

10、m是一個(gè)常量引用,引用到一個(gè)右值,但引用本身是一個(gè)持久對(duì)象(可以對(duì)其取地址),為左值。

區(qū)分清楚了左值與右值,我們?cè)賮?lái)看看左值引用。左值引用根據(jù)其修飾符的不同,可以分為非常量左值引用和常量左值引用。

非常量左值引用只能綁定到非常量左值,不能綁定到常量左值、非常量右值和常量右值。如果允許綁定到常量左值和常量右值,則非常量左值引用可以用于修改常量左值和常量右值,這明顯違反了其常量的含義。如果允許綁定到非常量右值,則會(huì)導(dǎo)致非常危險(xiǎn)的情況出現(xiàn)。因?yàn)榉浅A坑抑凳且粋€(gè)臨時(shí)對(duì)象,非常量左值引用可能會(huì)使用一個(gè)已經(jīng)被銷毀了的臨時(shí)對(duì)象。

常量左值引用可以綁定到所有類型的值,包括:非常量左值、常量左值、非常量右值和常量右值。

可以看出,使用左值引用時(shí),我們無(wú)法區(qū)分出綁定的是否是非常量右值的情況。那么,為什么要對(duì)非常量右值進(jìn)行區(qū)分呢?區(qū)分出來(lái)了,又有什么好處呢?這就牽涉到C++中一個(gè)著名的性能問(wèn)題——拷貝臨時(shí)對(duì)象??紤]下面的示例代碼。

vector<int> GetAllScores()
{
    vector<int> vctTemp;
    vctTemp.push_back(90);
    vctTemp.push_back(95);
    return vctTemp;
}

當(dāng)使用vector<int> vctScore = GetAllScores()進(jìn)行初始化時(shí),實(shí)際上調(diào)用了三次構(gòu)造函數(shù)。盡管有些編譯器可以采用RVO(Return Value Optimization)來(lái)進(jìn)行優(yōu)化,但優(yōu)化工作只在某些特定條件下才能進(jìn)行??梢钥吹剑厦婧芷胀ǖ囊粋€(gè)函數(shù)調(diào)用,由于存在臨時(shí)對(duì)象的拷貝,導(dǎo)致了額外的兩次拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù)的開銷。當(dāng)然,我們也可以修改函數(shù)的形式為:void GetAllScores(vector<int> &vctScore),但這并不一定就是我們需要的形式。另外,考慮下面字符串的連接操作:

string s1("Hello ");
string s = s1 + "W" + "o" + "r" + "l" + "d";

在對(duì)s進(jìn)行初始化時(shí),會(huì)產(chǎn)生大量的臨時(shí)對(duì)象,并涉及到大量字符串的拷貝操作,這顯然會(huì)影響程序的效率和性能。怎么解決這個(gè)問(wèn)題呢?如果我們能確定某個(gè)值是一個(gè)非常量右值(或者是一個(gè)以后不會(huì)再使用的左值),則我們?cè)谶M(jìn)行臨時(shí)對(duì)象的拷貝時(shí),可以不用拷貝實(shí)際的數(shù)據(jù),而只是“竊取”指向?qū)嶋H數(shù)據(jù)的指針(類似于STL中的auto_ptr,會(huì)轉(zhuǎn)移所有權(quán))。C++ 11中引入的右值引用,正好可用于標(biāo)識(shí)一個(gè)非常量右值。C++ 11中用&表示左值引用,用&&表示右值引用,比如:int &&a = 10。

右值引用根據(jù)其修飾符的不同,也可以分為:非常量右值引用和常量右值引用。

非常量右值引用只能綁定到非常量右值,不能綁定到非常量左值、常量左值和常量右值。如果允許綁定到非常量左值,則可能會(huì)錯(cuò)誤地竊取一個(gè)持久對(duì)象的數(shù)據(jù),而這是非常危險(xiǎn)的;如果允許綁定到常量左值和常量右值,則非常量右值引用可以用于修改常量左值和常量右值,這明顯違反了其常量的含義。

常量右值引用可以綁定到非常量右值和常量右值,不能綁定到非常量左值和常量左值(理由同上)。

使用案例

有了右值引用的概念,我們可以用它來(lái)實(shí)現(xiàn)下面的CMyString類。

#include <iostream>
using namespace std;

class CMyString
{
public:
    // 構(gòu)造函數(shù)
    CMyString(const char *pszSrc = NULL)
    {
        cout << "CMyString(const char *pszSrc = NULL)" << endl;
        if (pszSrc == NULL)
        {
            m_pData = new char[1];
            *m_pData = '\0';
        }
        else
        {
            m_pData = new char[strlen(pszSrc) + 1];
            strcpy(m_pData, pszSrc);
        }
    }

    // 拷貝構(gòu)造函數(shù)
    CMyString(const CMyString &s)
    {
        cout << "CMyString(const CMyString &s)" << endl;
        m_pData = new char[strlen(s.m_pData) + 1];
        strcpy(m_pData, s.m_pData);
    }

    // move構(gòu)造函數(shù)
    CMyString(CMyString &&s)
    {
        cout << "CMyString(CMyString &&s)" << endl;
        m_pData = s.m_pData;
        s.m_pData = NULL;
    }

    // 析構(gòu)函數(shù)
    ~CMyString()
    {
        cout << "~CMyString()" << endl;
        delete [] m_pData;
        m_pData = NULL;
    }

    // 拷貝賦值函數(shù)
    CMyString &operator =(const CMyString &s)
    {
        cout << "CMyString &operator =(const CMyString &s)" << endl;
        if (this != &s)
        {
            delete [] m_pData;
            m_pData = new char[strlen(s.m_pData) + 1];
            strcpy(m_pData, s.m_pData);
        }

        return *this;
    }

    // move賦值函數(shù)
    CMyString &operator =(CMyString &&s)
    {
        cout << "CMyString &operator =(CMyString &&s)" << endl;
        if (this != &s)
        {
            delete [] m_pData;
            m_pData = s.m_pData;
            s.m_pData = NULL;
        }

        return *this;
    }

private:
    char *m_pData;
};

int main()
{
    CMyString strText("Hello CSDN");
    CMyString strText2;
    strText2 = CMyString("BeiJing");
    return 0;
}

可以看到,上面我們添加了move版本的構(gòu)造函數(shù)和賦值函數(shù)。那么,添加了move版本后,對(duì)類的自動(dòng)生成規(guī)則有什么影響呢?唯一的影響就是,如果提供了move版本的構(gòu)造函數(shù),則不會(huì)生成默認(rèn)的構(gòu)造函數(shù)。另外,編譯器永遠(yuǎn)不會(huì)自動(dòng)生成move版本的構(gòu)造函數(shù)和賦值函數(shù),它們需要你手動(dòng)顯式地添加。

當(dāng)添加了move版本的構(gòu)造函數(shù)和賦值函數(shù)的重載形式后,某一個(gè)函數(shù)調(diào)用應(yīng)當(dāng)使用哪一個(gè)重載版本呢?下面是按照判決的優(yōu)先級(jí)列出的3條規(guī)則。

1、常量值只能綁定到常量引用上,不能綁定到非常量引用上。

2、左值優(yōu)先綁定到左值引用上,右值優(yōu)先綁定到右值引用上。

3、非常量值優(yōu)先綁定到非常量引用上。

當(dāng)給構(gòu)造函數(shù)或賦值函數(shù)傳入一個(gè)非常量右值時(shí),依據(jù)上面給出的判決規(guī)則,可以得出會(huì)調(diào)用move版本的構(gòu)造函數(shù)或賦值函數(shù)。而在move版本的構(gòu)造函數(shù)或賦值函數(shù)內(nèi)部,都是直接“移動(dòng)”了其內(nèi)部數(shù)據(jù)的指針。因?yàn)樗欠浅A坑抑?,是一個(gè)臨時(shí)對(duì)象,移動(dòng)了其內(nèi)部數(shù)據(jù)的指針不會(huì)導(dǎo)致任何問(wèn)題,它馬上就要被銷毀了,我們只是重復(fù)利用了其內(nèi)存,這樣就省去了拷貝數(shù)據(jù)的大量開銷。

一個(gè)需要注意的地方是:拷貝構(gòu)造函數(shù)可以通過(guò)直接調(diào)用*this = s來(lái)實(shí)現(xiàn),但move構(gòu)造函數(shù)卻不能。這是因?yàn)樵趍ove構(gòu)造函數(shù)中,s雖然是一個(gè)非常量右值引用,但其本身卻是一個(gè)左值(是持久對(duì)象,可以對(duì)其取地址),因此調(diào)用*this = s時(shí),會(huì)使用拷貝賦值函數(shù)而不是move賦值函數(shù),而這已與move構(gòu)造函數(shù)的語(yǔ)義不相符。要使語(yǔ)義正確,我們需要將左值綁定到非常量右值引用上,C++ 11提供了move函數(shù)來(lái)實(shí)現(xiàn)這種轉(zhuǎn)換,因此我們可以修改為*this = move(s),這樣move構(gòu)造函數(shù)就會(huì)調(diào)用move賦值函數(shù)。

應(yīng)用場(chǎng)景

1、智能指針。

C++ 11標(biāo)準(zhǔn)庫(kù)中的std::unique_ptr和std::shared_ptr等智能指針利用了右值引用來(lái)安全有效地轉(zhuǎn)移所有權(quán)。

2、容器。

C++ STL容器,比如:std::vector、std::string等,在C++11之后都開始支持移動(dòng)構(gòu)造和移動(dòng)賦值,從而避免了在添加元素或重新分配內(nèi)存時(shí)不必要的數(shù)據(jù)拷貝。

3、字符串字面值。

C++ 11中引入了std::string_view,它可以通過(guò)右值引用高效地引用字符串字面值,或現(xiàn)有std::string對(duì)象的內(nèi)容,而無(wú)需復(fù)制。

4、RAII原則強(qiáng)化。

RAII,也就是資源獲取即初始化(英文為:Resource Acquisition Is Initialization),是C++中一種重要的資源管理手段。右值引用使資源在生命周期結(jié)束時(shí)能被自動(dòng)回收,并允許在對(duì)象之間高效地“移動(dòng)”資源控制權(quán)。

總結(jié)

右值引用無(wú)疑是C++ 11的一項(xiàng)重大革新,它不僅提高了程序的運(yùn)行效率,也極大地簡(jiǎn)化了程序員對(duì)資源管理的復(fù)雜度。掌握這一特性對(duì)于寫出更現(xiàn)代、更高效的C++代碼至關(guān)重要。同時(shí),隨著C++后續(xù)版本的發(fā)展,右值引用在標(biāo)準(zhǔn)庫(kù)中的使用越來(lái)越廣泛,成為現(xiàn)代C++開發(fā)者的必備知識(shí)之一。

到此這篇關(guān)于C++ 11新特性之右值引用使用案例與應(yīng)用場(chǎng)景的文章就介紹到這了,更多相關(guān)C++ 11新特性右值引用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解MFC/C++調(diào)用易語(yǔ)言的整數(shù)型和文本型與VS2010互動(dòng)

    詳解MFC/C++調(diào)用易語(yǔ)言的整數(shù)型和文本型與VS2010互動(dòng)

    在本篇文章里我們給大家分享了MFC/C++調(diào)用易語(yǔ)言的整數(shù)型和文本型與VS2010互動(dòng)相關(guān)知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們可以參考下。
    2018-11-11
  • C++中std::setw()的用法解讀

    C++中std::setw()的用法解讀

    這篇文章主要介紹了C++中std::setw()的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C語(yǔ)言代碼實(shí)現(xiàn)簡(jiǎn)單掃雷小游戲

    C語(yǔ)言代碼實(shí)現(xiàn)簡(jiǎn)單掃雷小游戲

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)掃雷游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • VSCode+Qt+CMake詳細(xì)教程

    VSCode+Qt+CMake詳細(xì)教程

    本文詳解如何在VSCode中搭建Qt與CMake開發(fā)環(huán)境,涵蓋安裝步驟、配置Qt路徑、編寫CMakeLists.txt及項(xiàng)目構(gòu)建運(yùn)行流程,強(qiáng)調(diào)擴(kuò)展工具鏈的使用,助力實(shí)現(xiàn)高效跨平臺(tái)Qt C++開發(fā),本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2025-08-08
  • C++讀寫INI配置文件的類實(shí)例

    C++讀寫INI配置文件的類實(shí)例

    這篇文章主要介紹了C++讀寫INI配置文件的類,實(shí)例分析了C++操作ini配置文件的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • C++實(shí)現(xiàn)的一個(gè)可以寫遞歸lambda的Y函數(shù)

    C++實(shí)現(xiàn)的一個(gè)可以寫遞歸lambda的Y函數(shù)

    這篇文章主要介紹了C++實(shí)現(xiàn)的一個(gè)可以寫遞歸lambda的Y函數(shù),在Y函數(shù)的幫助,這個(gè)lambda表達(dá)是可以成功看到自己,然后遞歸調(diào)用的,需要的朋友可以參考下
    2014-07-07
  • 詳解C語(yǔ)言中結(jié)構(gòu)體(struct)的用法

    詳解C語(yǔ)言中結(jié)構(gòu)體(struct)的用法

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言中結(jié)構(gòu)體(struct)的用法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C語(yǔ)言有一定幫助,需要的可以參考一下
    2022-08-08
  • VScode編譯C++ 頭文件顯示not found的問(wèn)題

    VScode編譯C++ 頭文件顯示not found的問(wèn)題

    這篇文章主要介紹了VScode編譯C++ 頭文件顯示not found的問(wèn)題,本文給大家分享問(wèn)題解決方法,通過(guò)截圖的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2020-03-03
  • MFC繪制不規(guī)則窗體的方法

    MFC繪制不規(guī)則窗體的方法

    這篇文章主要介紹了MFC繪制不規(guī)則窗體的方法,涉及MFC窗體操作的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • C++ 右值語(yǔ)義相關(guān)總結(jié)

    C++ 右值語(yǔ)義相關(guān)總結(jié)

    這篇文章主要介紹了C++ 右值語(yǔ)義的的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用c++,感興趣的朋友可以了解下
    2021-02-02

最新評(píng)論

色达县| 江山市| 泸水县| 中阳县| 镶黄旗| 青河县| 钦州市| 敖汉旗| 天等县| 长乐市| 海原县| 乐昌市| 黄大仙区| 高淳县| 阜新市| 昂仁县| 阿城市| 德化县| 纳雍县| 金沙县| 和林格尔县| 奉化市| 巨鹿县| 班戈县| 宜川县| 武定县| 深州市| 北票市| 房产| 永寿县| 通辽市| 舞钢市| 垦利县| 阳谷县| 隆尧县| 唐河县| 三台县| 大城县| 莱芜市| 曲沃县| 册亨县|