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

