C++ 編譯器調(diào)用“復(fù)制構(gòu)造函數(shù)”或“移動(dòng)構(gòu)造函數(shù)”時(shí)的自動(dòng)選擇分析

??眾所周知,當(dāng)類的對象作為函數(shù)返回值的時(shí)候,函數(shù)會(huì)調(diào)用類的復(fù)制構(gòu)造函數(shù)或移動(dòng)構(gòu)造函數(shù),來構(gòu)造一個(gè)臨時(shí)無名對象返回主函數(shù)中。

??當(dāng)一個(gè)類中既有復(fù)制構(gòu)造函數(shù),又有移動(dòng)構(gòu)造函數(shù)的時(shí)候,函數(shù)在返回時(shí),編譯器調(diào)用的是復(fù)制構(gòu)造函數(shù)還是移動(dòng)構(gòu)造函數(shù)?調(diào)用的依據(jù)又是什么?首先來看一個(gè)例子:

#include<iostream>
using namespace std;

class IntNum{
private:
    int *xptr;
public:
    //構(gòu)造函數(shù)
    IntNum(int x = 0) : xptr(new int(x)){
        //構(gòu)造函數(shù)的任務(wù)直接在初始化列表里完成,即動(dòng)態(tài)分配int變量,并把變量地址賦給私有數(shù)據(jù)成員指針xptr
        cout << "Calling copy constructor..." << endl;
    }

    //復(fù)制構(gòu)造函數(shù)
    IntNum(const IntNum &n) :xptr(new int(*n.xptr)){
        /*在初始化列表中,動(dòng)態(tài)分配int變量(初始化參數(shù)為被調(diào)用來進(jìn)行復(fù)制構(gòu)造的IntNum對象里的動(dòng)態(tài)變量的值,*n.xptr即*(n.xptr)),
        并把變量地址賦給私有數(shù)據(jù)成員指針xptr*/
        cout << "Calling copy constructor..." << endl;
    }

    //移動(dòng)構(gòu)造函數(shù)
    IntNum(IntNum &&n) :xptr(n.xptr){
        //初始化列表將被移動(dòng)IntNum對象的指針xptr的地址賦給當(dāng)前創(chuàng)建的新對象指針xptr,那么原對象的動(dòng)態(tài)分配空間就“繼承”給了當(dāng)前對象
        /*全局函數(shù)getNum中定義一個(gè)IntNum局部對象a,調(diào)用的是復(fù)制構(gòu)造函數(shù);return a則是調(diào)用移動(dòng)構(gòu)造函數(shù),構(gòu)造一個(gè)臨時(shí)無名對象返回主函數(shù)中;

        &&是右值引用,右值引用的好處是,只將臨時(shí)對象(a)的資源做了淺拷貝,不需要對其進(jìn)行深拷貝,從而避免了額外的拷貝,提高性能。*/
        n.xptr = nullptr;//置為空指針
        cout << "Calling move constructor..." << endl;
    }

    //析構(gòu)函數(shù)
    ~IntNum(){
        delete xptr;
        cout << "Destructing..." << endl;
    }

    //成員函數(shù)
    int getInt(){
        return *xptr;
    }
};

//一個(gè)全局函數(shù),返回值為IntNum類對象
IntNum getNum(){
    IntNum a;//這里調(diào)用的是類的構(gòu)造函數(shù)
    return a;/*這里編譯器自動(dòng)調(diào)用移動(dòng)構(gòu)造函數(shù),為什么沒有調(diào)用復(fù)制構(gòu)造函數(shù)?
    是因?yàn)椋?dāng)對象a將作為實(shí)參傳進(jìn)復(fù)制構(gòu)造函數(shù)/移動(dòng)構(gòu)造函數(shù)時(shí),編譯器會(huì)對對象a做一個(gè)判斷,
    如果對象a是一個(gè)臨時(shí)對象(局部對象),則編譯器認(rèn)為構(gòu)造函數(shù)只需要對象a作為右值傳入,不需要對象a作為左值傳入構(gòu)造函數(shù),
    當(dāng)作為右值傳入函數(shù)時(shí),移動(dòng)構(gòu)造函數(shù)只是將臨時(shí)對象(a)的資源做了淺拷貝,不需要對其進(jìn)行深拷貝,從而避免了額外的拷貝,提高性能。*/
}

int main(){
    cout << getNum().getInt() << endl;
    return 0;
}

??哎呀,我對代碼的理解已經(jīng)寫到了代碼中了,就懶得贅述了??。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容