国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

c++積累8-右值引用、移動(dòng)語(yǔ)義

這篇具有很好參考價(jià)值的文章主要介紹了c++積累8-右值引用、移動(dòng)語(yǔ)義。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1、右值引用

1.1 背景

c++98中的引用很常見(jiàn),就是給變量取個(gè)別名,具體可以參考c++積累7
在c++11中,增加了右值引用的概念,所以c++98中的引用都稱為左值引用

1.2 定義

右值引用就是給右值取個(gè)名字,右值有了名字之后就成了普通變量,可以像使用左值一樣使用。

語(yǔ)法:數(shù)據(jù)類型&& 變量名=右值

示例:

#include <iostream>

class AA {
public:
    int m_a = 9;
};

AA getTemp() {
    return AA();
}

int main() {
    using namespace std;

    int &&a = 3; // 3是右值,給它起個(gè)名字叫a
    int b = 8; // b 是左值, 8是右值
    int &&c = b + 5; // b+5是右值,給它取個(gè)名字叫c

    AA &&aa = getTemp();// getTemp()返回值是右值(臨時(shí)變量),給它起個(gè)名字叫aa

    cout << "a= " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;
    cout << "aa.m_a= " << aa.m_a << endl;

    return 0;
}

c++積累8-右值引用、移動(dòng)語(yǔ)義

1.3 常量左值引用

常量左值引用是一個(gè)萬(wàn)能的引用類型,它可以綁定非常量左值、常量做值、右值,在綁定右值的時(shí)候,常量左值引用可以像右值引用一樣將右值的生命期延長(zhǎng),缺點(diǎn)是只能讀不能改

    int a = 1;
    const int &ra = a; // a是非常量左值
    const int b = 2;
    const int &rb = b; // b是常量左值
    const int &rc = 1; // 1是右值

2、移動(dòng)語(yǔ)義

2.1 背景

如果一個(gè)對(duì)象中有堆區(qū)資源,需要編寫拷貝構(gòu)造函數(shù)和賦值函數(shù),實(shí)現(xiàn)深拷貝。
深拷貝把對(duì)象中堆區(qū)資源復(fù)制了一份,如果資源(被拷貝的資源)是臨時(shí)對(duì)象,拷貝完就沒(méi)有什么意義了,這樣會(huì)造成沒(méi)有意義的資源申請(qǐng)和釋放操作。
如果能夠直接使用對(duì)象擁有的資源,可以節(jié)省資源申請(qǐng)和釋放的時(shí)間。c++11增加的移動(dòng)語(yǔ)義就能夠做到這一點(diǎn)。

2.2 定義

移動(dòng)語(yǔ)義增加兩個(gè)構(gòu)造函數(shù):移動(dòng)構(gòu)造函數(shù) 、 移動(dòng)賦值函數(shù)
移動(dòng)構(gòu)造函數(shù)語(yǔ)法:
類名(類名&& 源對(duì)象){…}
移動(dòng)賦值函數(shù)語(yǔ)法:
類名& operator=(類名&& 源對(duì)象){…}

demo:

#include <iostream>
#include <string.h>

using namespace std;

class AA {
public:
    int *m_data = nullptr; //數(shù)據(jù)成員,指向堆區(qū)資源的指針
    AA() = default; // 啟用默認(rèn)構(gòu)造函數(shù)

    void alloc() {  // 給數(shù)據(jù)成員m_data分配內(nèi)存
        m_data = new int;  // 分配內(nèi)存
        memset(m_data, 0, sizeof(int)); //初始化已分配的內(nèi)存
    }

    AA(const AA &a) {  //拷貝構(gòu)造函數(shù) - 拷貝語(yǔ)義
        cout << "調(diào)用了拷貝構(gòu)造函數(shù) 。\n";  // 顯示自己被調(diào)用的日志
        if (m_data == nullptr) alloc(); // 如果沒(méi)有分配內(nèi)存,就分配
        memcpy(m_data, a.m_data, sizeof(int)); //把數(shù)據(jù)從源對(duì)象中拷貝過(guò)來(lái)
    }

    AA(AA &&a) {  //拷貝構(gòu)造函數(shù) - 移動(dòng)語(yǔ)義
        cout << "調(diào)用了移動(dòng)語(yǔ)義拷貝構(gòu)造函數(shù) 。\n";  // 顯示自己被調(diào)用的日志
        if (m_data != nullptr) delete m_data; // 如果已經(jīng)分配內(nèi)存,先釋放
        m_data = a.m_data; // 把資源從源對(duì)象中轉(zhuǎn)移過(guò)來(lái)
        a.m_data = nullptr; // 把源對(duì)象中的指針置空
    }

    AA &operator=(const AA &a) { //賦值函數(shù) - 拷貝語(yǔ)義
        cout << "調(diào)用了賦值函數(shù)。\n"; // 顯示自己被調(diào)用的日志
        if (this == &a) return *this; // 避免自我賦值
        if (m_data == nullptr) alloc(); // 如果沒(méi)有分配內(nèi)存,就分配
        memcpy(m_data, a.m_data, sizeof(int)); // 把數(shù)據(jù)從源對(duì)象中拷貝過(guò)來(lái)
        return *this;
    }

    AA &operator=(AA &&a) { //賦值函數(shù) - 移動(dòng)語(yǔ)義
        cout << "調(diào)用了移動(dòng)語(yǔ)義賦值函數(shù)。\n"; // 顯示自己被調(diào)用的日志
        if (this == &a) return *this; // 避免自我賦值
        if (m_data != nullptr) delete m_data; // 如果已經(jīng)分配內(nèi)存,先釋放
        m_data = a.m_data; // 把資源從源對(duì)象中轉(zhuǎn)移過(guò)來(lái)
        a.m_data = nullptr; // 把源對(duì)象中的指針置空
        return *this;
    }

    ~AA() { // 析構(gòu)函數(shù)
        cout << "調(diào)用析構(gòu)函數(shù)" << endl;
        if (m_data != nullptr) {
            delete m_data;
            m_data == nullptr;
        }
    }

};

int main() {
    AA a1; // 創(chuàng)建對(duì)象a1
    a1.alloc(); // 分配堆區(qū)資源
    *a1.m_data = 3; // 給堆區(qū)內(nèi)存賦值
    cout << "*a1.m_data = " << *a1.m_data << ",addr = " << a1.m_data << endl;

    AA a2 = a1; // 調(diào)用拷貝構(gòu)造函數(shù) - 這個(gè)地方a1是左值就調(diào)用拷貝語(yǔ)義構(gòu)造函數(shù),如果是右值,則調(diào)用移動(dòng)語(yǔ)義構(gòu)造函數(shù)
    cout << "*a2.m_data = " << *a2.m_data << ",addr = " << a2.m_data << endl;

    AA a3;
    a3 = a1; // 調(diào)用賦值函數(shù)
    cout << "*a3.m_data = " << *a3.m_data << ",addr = " << a3.m_data << endl;

    auto f = [] { // 返回AA類對(duì)象的lambda函數(shù)
        AA aa;
        aa.alloc();
        *aa.m_data = 10;
        return aa;
    };
    AA a4 = f(); // lambda函數(shù)返回臨時(shí)對(duì)象,是右值,將調(diào)用移動(dòng)構(gòu)造函數(shù)
    cout << "*a4.m_data = " << *a4.m_data << ",addr = " << a4.m_data << endl;

    AA a6;
    a6 = f(); // lambda函數(shù)返回臨時(shí)對(duì)象,是右值,將調(diào)用移動(dòng)賦值函數(shù)
    cout << "*a6.m_data = " << *a6.m_data << ",addr = " << a6.m_data << endl;

    return 0;
}

c++積累8-右值引用、移動(dòng)語(yǔ)義

2.3、說(shuō)明

1 std::move() 左值轉(zhuǎn)換為右值
對(duì)于一個(gè)左值,會(huì)調(diào)用拷貝構(gòu)造函數(shù),但是有些左值是局部變量,聲明周期也很短,我們也想使用移動(dòng),C++為了解決這種問(wèn)題,提供了std::move()方法來(lái)將左值轉(zhuǎn)義為右值,從而方便使用移動(dòng)語(yǔ)義。
左值對(duì)象被轉(zhuǎn)移資源后,不會(huì)立刻析構(gòu),只有在離開(kāi)自己的作用域的時(shí)候才會(huì)析構(gòu),如果繼續(xù)使用左值的資源,可能會(huì)發(fā)生意想不到的錯(cuò)誤。
2 沒(méi)有提供移動(dòng)構(gòu)造、賦值函數(shù),使用拷貝構(gòu)造、賦值函數(shù)
如果沒(méi)有提供移動(dòng)構(gòu)造/賦值函數(shù),只提供了拷貝構(gòu)造/賦值函數(shù),編譯器找不到移動(dòng)構(gòu)造/賦值函數(shù)就會(huì)去尋找拷貝構(gòu)造/賦值函數(shù)
3 c++11中的所有容器都實(shí)現(xiàn)了移動(dòng)語(yǔ)義,避免對(duì)含有資源的對(duì)象發(fā)生無(wú)畏的拷貝
4 移動(dòng)語(yǔ)義對(duì)于擁有資源(如內(nèi)存、文件句柄)的對(duì)象有效,如果是基本類型,使用移動(dòng)語(yǔ)義沒(méi)有意義

3、完美轉(zhuǎn)發(fā) std::forward()

如果模版中(包含類模版和函數(shù)模版)函數(shù)的參數(shù)寫成 T&& 參數(shù)名, 那么函數(shù)既可以接收左值引用,右可以接受右值引用。

模版函數(shù):std::forward(參數(shù))用于轉(zhuǎn)發(fā)參數(shù)。如果參數(shù)是一個(gè)右值,轉(zhuǎn)發(fā)之后仍是右值引用,如果參數(shù)是一個(gè)左值,轉(zhuǎn)發(fā)之后仍是左值引用。

#include <iostream>

using namespace std;
void func1(int &i ){
    cout<< "參數(shù)是左值"<< i << endl;
}

void func1(int && i){
    cout << "參數(shù)是右值" << i << endl;
}

//template<typename T>
//void func2(T &i){
//    cout << "func2 1111" << endl;
//    func1(i);
//}
//
//template<typename T>
//void func2(T&& i){
//    cout << "func2 2222" << endl;
//    func1(move(i));
//}

template<typename T>
void func2(T&& i){
    func1(forward<T>(i));
}

//void func2(int& i){
//    func1(i);
//}
//
//void func2(int&&i ){
//    func1(move(i));
//}

int main(void) {
    int a = 3;

    func2(a);
    func2(9);
}

std::forward文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-421890.html

到了這里,關(guān)于c++積累8-右值引用、移動(dòng)語(yǔ)義的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • C++右值引用(左值表達(dá)式、右值表達(dá)式)(移動(dòng)語(yǔ)義、完美轉(zhuǎn)發(fā)(右值引用+std::forward))(有問(wèn)題懸而未決)

    C++右值引用(左值表達(dá)式、右值表達(dá)式)(移動(dòng)語(yǔ)義、完美轉(zhuǎn)發(fā)(右值引用+std::forward))(有問(wèn)題懸而未決)

    在 C++ 中,表達(dá)式可以分為左值表達(dá)式和右值表達(dá)式。左值表達(dá)式指的是可以出現(xiàn)在賦值語(yǔ)句左邊的表達(dá)式,例如變量、數(shù)組元素、結(jié)構(gòu)體成員等;右值表達(dá)式指的是不能出現(xiàn)在賦值語(yǔ)句左邊的表達(dá)式,例如常量、臨時(shí)對(duì)象、函數(shù)返回值等。 右值是指將要被銷毀的臨時(shí)對(duì)象或

    2024年02月04日
    瀏覽(23)
  • 【C++】 C++11(右值引用,移動(dòng)語(yǔ)義,bind,包裝器,lambda,線程庫(kù))

    【C++】 C++11(右值引用,移動(dòng)語(yǔ)義,bind,包裝器,lambda,線程庫(kù))

    C++11是C++語(yǔ)言的一次重大更新版本,于2011年發(fā)布,它包含了一些非常有用的新特性,為開(kāi)發(fā)人員提供了更好的編程工具和更好的編程體驗(yàn),使得編寫高效、可維護(hù)、安全的代碼更加容易。 一些C++11的新增特性包括: 強(qiáng)制類型枚舉,使得枚舉類型的通常行為更加可靠和容易控制

    2024年02月10日
    瀏覽(20)
  • C++ Primer閱讀筆記--對(duì)象移動(dòng)(右值引用、移動(dòng)迭代器和引用限定符的使用)

    目錄 1--右值引用 2--std::move 3--移動(dòng)構(gòu)造函數(shù) 4--移動(dòng)賦值運(yùn)算符 5--移動(dòng)迭代器 6--引用限定符 ? ? ? ? 右值引用必須綁定到右值的引用,通過(guò) 獲得右值引用; ????????右值引用只能綁定到 臨時(shí)對(duì)象 (即將被銷毀的對(duì)象),即所引用的對(duì)象將要被銷毀,對(duì)象沒(méi)有其他用戶;

    2024年02月10日
    瀏覽(39)
  • 【C++干貨鋪】C++11新特性——右值引用、移動(dòng)構(gòu)造、完美轉(zhuǎn)發(fā)

    【C++干貨鋪】C++11新特性——右值引用、移動(dòng)構(gòu)造、完美轉(zhuǎn)發(fā)

    ========================================================================= 個(gè)人主頁(yè)點(diǎn)擊直達(dá):小白不是程序媛 C++系列專欄:C++干貨鋪 代碼倉(cāng)庫(kù):Gitee ========================================================================= 目錄 左值與左值引用 右值與右值引用 左值引用和右值引用的比較 ?左值引用總結(jié):

    2024年01月25日
    瀏覽(19)
  • C++右值引用,右值引用與const引用的區(qū)別

    左值:可以取地址的、有名字的變量,有持久性; 右值:一般是不可尋址的常量,或在表達(dá)式求值過(guò)程中創(chuàng)建的無(wú)名臨時(shí)對(duì)象,短暫性的。 C++11新增了另一種引用——右值引用。這種引用可指向右值,使用聲明。 右值引用只能引用臨時(shí)變量和常量值。 const引用:可以引用普

    2024年01月18日
    瀏覽(26)
  • 詳解 C++ 左值、右值、左值引用以及右值引用

    詳解 C++ 左值、右值、左值引用以及右值引用

    左值是一個(gè)表示數(shù)據(jù)的表達(dá)式,比如: 變量名、解引用的指針變量 。一般地,我們可以 獲取它的地址 和 對(duì)它賦值 ,但被 const 修飾后的左值,不能給它賦值,但是仍然可以取它的地址。 總體而言,可以取地址的對(duì)象就是左值。 右值也是一個(gè)表示數(shù)據(jù)的表達(dá)式,比如: 字面

    2023年04月08日
    瀏覽(31)
  • 【C++11】 initializer_list | 右值引用 | 移動(dòng)構(gòu)造 | 完美轉(zhuǎn)發(fā)

    【C++11】 initializer_list | 右值引用 | 移動(dòng)構(gòu)造 | 完美轉(zhuǎn)發(fā)

    { } 初始化 C++11 擴(kuò)大了括號(hào)括起的列表(初始化列表)的使用范圍,使其可用于所有的內(nèi)置類型和用戶自定義類型, 使用初始化列表,可添加等號(hào)(=),也可不添加 將1賦值給x1,x2處省略了賦值符號(hào),將5賦值給x2 同樣也可以將new開(kāi)辟4個(gè)int的空間初始化為0 創(chuàng)建對(duì)象時(shí),可以使用列

    2024年02月08日
    瀏覽(23)
  • [開(kāi)發(fā)語(yǔ)言][c++]:左值、右值、左值引用、右值引用和std::move()

    寫在前面: 如果你也被 左值、右值、左值引用、右值引用和std::move 搞得焦頭爛額,相關(guān)概念和理解不夠深入,或者認(rèn)識(shí)模棱兩可,那么這篇文章將非常的適合你,耐心閱讀,相信一定會(huì)有所收獲~~ 左值: 可以取地址、位于等號(hào)左邊 – 表達(dá)式結(jié)束后依然存在的持久對(duì)象

    2024年02月02日
    瀏覽(14)
  • C++右值引用(&&)

    右值引用是 C++11 新增的特性之一,它是我們?cè)谌粘i_(kāi)發(fā)工作中不斷接觸到的特性之一。本篇博客將對(duì)右值引用的定義、使用場(chǎng)景以及使用方法進(jìn)行詳細(xì)介紹。 右值引用是一種新的引用類型,“右值引用” 又被稱為“具名右值引用”(Named Rvalue Reference),其定義形式為:Type v

    2024年02月07日
    瀏覽(21)
  • 【C++】右值引用

    【C++】右值引用

    引用是給對(duì)象取別名,本質(zhì)是為了減少拷貝 。以前我們學(xué)習(xí)的引用都是左值引用,右值引用是C++11新增的語(yǔ)法,它們的共同點(diǎn)都是給對(duì)象取別名。既然如此,有了左值引用,為什么還要有右值引用?右值引用具體是怎樣的?以及它有哪些應(yīng)用場(chǎng)景?接下來(lái),會(huì)詳細(xì)分析~~ 左值

    2024年04月11日
    瀏覽(22)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包