C++右值引用問(wèn)題解決
1、右值引用與函數(shù)重載
class Int
{
int value;
public:
Int(int x = 0) :value(x) { cout << "create " << this << endl; }
~Int() { cout << "destroy " << this << endl; }
Int(const Int& it) :value(it.value)
{
cout << &it << " copy " << this << endl;
}
Int& operator=(const Int& it)
{
if (this != &it)
{
value = it.value;
}
cout << &it << " operator= " << this << endl;
return *this;
}
void PrintValue()const
{
cout<<"value: "<<value<<endl;
}
Int& SetValue(int x)
{
value=x;
return *this;
}
};
//void func(Int a){}//會(huì)和void fun(Int&& c)形成二義性,原因是無(wú)名對(duì)象即可以賦值給對(duì)象也可以賦值給右值引用
void func(Int& a)
{
cout<<"lvalue_reference"<<endl;
}
void func(const Int& b)
{
cout<<"lvalue_const_reference"<<endl;
}
void func(Int&& c)
{
cout<<"rvalue_reference"<<endl;
}
int main()
{
Int x(10);
const Int y(20);
func(x);//優(yōu)先匹配func(Int& a),沒(méi)有就匹配func(const Int& b)
func(y);//只能匹配func(const Int& b)
func(Int(30));//優(yōu)先匹配func(Int&& c),沒(méi)有就匹配func(const Int& b)
Int z(10);
func((Int&&)z);//調(diào)用func(Int&& c)
func((const Int&&)z);//調(diào)用func(const Int& b)
return 0;
}2、右值引用優(yōu)化性能,避免深拷貝
class MyString
{
private:
char* str;
public:
MyString(const char* p=nullptr):str(nullptr)
{
if(p!=nullptr)
{
int n=strlen(p)+1;
str=new char[n];
strcpy_s(str,n,p);
}
cout<<"Create MyString"<<this<<endl;
}
~MyString()
{
if(str!=nullptr)
{
delete[] str;
str=nullptr;
}
str=nullptr;
}
MyString(const MyString& st):str(nullptr)//深拷貝
{
if(st.str!=nullptr)
{
int n=strlen(st.str)+1;
str=new char[n];
strcpy_s(str,n,st.str);
}
cout<<"Copy Create MyString"<<this<<endl;
}
MyString& operator=(const MyString& st)//深賦值
{
if(this==&st||str==st.str)
{
return *this;
}
delete[] str;//str為空時(shí)也可以進(jìn)行delete,因?yàn)閐elete調(diào)用free,在free中會(huì)進(jìn)行判空
int n=strlen(st.str)+1;
str=new char[n];
strcpy_s(str,n,st.str);
cout<<this<<"operator= MyString"<<&st<<endl;
return *this;
}
void Print()const
{
if(str!=nullptr)
{
cout<<str<<endl;
}
}
};2.1使用深拷貝和深復(fù)制會(huì)對(duì)堆區(qū)空間造成巨大影響
MyString func(const char* p)
{
MyString tmp(p);
return tmp;
}
int main()
{
MyString s1("hello");
s1=func("helloworld");
s1.Print();
return 0;
}
在main函數(shù)中能看見(jiàn)的字符串"hello"和"helloworld"均存放在.data區(qū),p指針指向的也是.data區(qū)的"helloworld"。運(yùn)行時(shí)進(jìn)入主函數(shù),首先創(chuàng)建s1對(duì)象,在堆區(qū)空間申請(qǐng)空間存放字符串"hello",s1.str指向該堆區(qū)空間。
再調(diào)用func()函數(shù),進(jìn)入func()函數(shù)先創(chuàng)建tmp對(duì)象,在堆區(qū)申請(qǐng)空間存放字符串"helloworld",tmp.str指向該堆區(qū)空間。
返回時(shí),使用tmp對(duì)象構(gòu)建將亡值對(duì)象xvalue,同樣的,在堆區(qū)申請(qǐng)和tmp所申請(qǐng)大小相同的空間,將字符串"helloworld"賦值過(guò)去進(jìn)行存放,xvalue.str指向該堆區(qū)空間。需要注意的是xvalue這個(gè)將亡值對(duì)象是在main棧幀中創(chuàng)建的,而不是func()函數(shù)棧幀中。創(chuàng)建完將亡值對(duì)象后,func()函數(shù)結(jié)束銷毀tmp對(duì)象,將其所指向的堆區(qū)空間進(jìn)行釋放。
再回到主函數(shù),將該將亡值對(duì)象賦值給s1對(duì)象時(shí),調(diào)用賦值函數(shù)。首先申請(qǐng)和將亡值對(duì)象申請(qǐng)大小相同的空間,將字符串"helloworld"賦值過(guò)去進(jìn)行存放,釋放s1對(duì)象開(kāi)始指向的堆區(qū)空間,之后再將s1.str重新指向新申請(qǐng)的空間。析構(gòu)所有對(duì)象這樣整個(gè)程序結(jié)束。
由此看來(lái),深拷貝在一些情況下嚴(yán)重干擾堆空間,對(duì)其不停的申請(qǐng)和釋放。
2.2使用移動(dòng)拷貝構(gòu)造和移動(dòng)賦值提升性能(移動(dòng)資源)
//移動(dòng)拷貝構(gòu)造
MyString(MyString&& st):str(nullptr)
{
str=st.str;
st.str=nullptr;
cout<<"Move Copy Create"<<endl;
}
//移動(dòng)賦值
MyString& operator=(MyString&& st)
{
if(this==&st)return *this;
delete[] str;
str=st.str;
st.str=nullptr;
cout<<"Move Operator= "<<endl;
return *this;
}加入移動(dòng)拷貝構(gòu)造和移動(dòng)賦值后再執(zhí)行下面代碼:
MyString func(const char* p)
{
MyString tmp(p);
return tmp;
}
int main()
{
MyString s1("hello");
s1=func("helloworld");
s1.Print();
return 0;
}同樣的,運(yùn)行時(shí)進(jìn)入主函數(shù),首先創(chuàng)建s1對(duì)象,在堆區(qū)空間申請(qǐng)空間存放字符串"hello",s1.str指向該堆區(qū)空間。
再調(diào)用func()函數(shù),進(jìn)入func()函數(shù)先創(chuàng)建tmp對(duì)象,在堆區(qū)申請(qǐng)空間存放字符串"helloworld",tmp.str指向該堆區(qū)空間。
返回時(shí)tmp為左值對(duì)象,但系統(tǒng)認(rèn)為在func函數(shù)中定義的局部對(duì)象tmp其生存期只在該函數(shù)中,使用return返回tmp對(duì)象時(shí),認(rèn)為是要將tmp的資源進(jìn)行移動(dòng),就會(huì)將其看成是將亡值。(系統(tǒng)“作弊”)
所以在func函數(shù)返回前會(huì)調(diào)用移動(dòng)拷貝構(gòu)造函數(shù)將tmp對(duì)象的資源移動(dòng)給創(chuàng)建的xvalue將亡值,func函數(shù)結(jié)束,析構(gòu)tmp對(duì)象。
回到main函數(shù)時(shí),將將亡值xvalue賦值給s1對(duì)象時(shí),調(diào)用移動(dòng)賦值函數(shù),將xvalue的資源再次移動(dòng)給s1對(duì)象,賦值結(jié)束后xvalue將亡值對(duì)象消亡,打印s1的內(nèi)容,析構(gòu)所有對(duì)象程序結(jié)束。
在這個(gè)過(guò)程中,并沒(méi)有多次反復(fù)的申請(qǐng)空間和釋放空間,而是將申請(qǐng)的空間在多個(gè)對(duì)象之間進(jìn)行移動(dòng),這樣就使得程序的性能提高。
如果將str設(shè)置為公有,即可在func和主函數(shù)中打印str的值,會(huì)發(fā)現(xiàn)tmp和func("helloworld")以及賦值完成后的s1的str值都相同,說(shuō)明他們一直指向同一塊內(nèi)存空間。
到此這篇關(guān)于C++右值引用問(wèn)題的文章就介紹到這了,更多相關(guān)C++右值引用問(wèn)題內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
linux根據(jù)pid獲取進(jìn)程名和獲取進(jìn)程pid(c語(yǔ)言獲取pid)
status文件,第一行的Name即為進(jìn)程名,C程序?qū)崿F(xiàn)根據(jù)PID獲取進(jìn)程名和根據(jù)進(jìn)程名獲取PID,大家參考使用吧2013-12-12
C++實(shí)現(xiàn)圖書(shū)管理系統(tǒng)(文件操作與類)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)圖書(shū)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C++?Boost?weak_ptr智能指針超詳細(xì)講解
智能指針是一種像指針的C++對(duì)象,但它能夠在對(duì)象不使用的時(shí)候自己銷毀掉。雖然STL提供了auto_ptr,但是由于不能同容器一起使用(不支持拷貝和賦值操作),因此很少有人使用。它是Boost各組件中,應(yīng)用最為廣泛的一個(gè)2022-11-11
Qt編寫(xiě)地圖之實(shí)現(xiàn)跨平臺(tái)功能
這篇文章主要介紹了如何利用Qt編寫(xiě)地圖應(yīng)用時(shí)實(shí)現(xiàn)跨平臺(tái)功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-02-02
C++下如何將TensorFlow模型封裝成DLL供C#調(diào)用
這篇文章主要介紹了C++下如何將TensorFlow模型封裝成DLL供C#調(diào)用問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
C語(yǔ)言簡(jiǎn)單實(shí)現(xiàn)門(mén)禁系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言簡(jiǎn)單實(shí)現(xiàn)門(mén)禁系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01

