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