??眾所周知,當(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)寫到了代碼中了,就懶得贅述了??。