一、Big Three
第二周是 class with pointer members的內(nèi)容,用 string 來講解。
對(duì)于帶指針的類有關(guān)鍵三個(gè)特殊函數(shù),Big Three(三巨頭)
- 拷貝構(gòu)造函數(shù)
- 拷貝賦值函數(shù)
- 析構(gòu)函數(shù)
對(duì)于帶指針的類,存儲(chǔ)的數(shù)據(jù)是指針,在構(gòu)造函數(shù)要完成申請(qǐng)內(nèi)存和拷貝字符串。析構(gòu)函數(shù)完成內(nèi)存的釋放。
二、拷貝構(gòu)造函數(shù)和拷貝賦值函數(shù)
2.1 淺拷貝與深拷貝
對(duì)于字符串常量,C++用獨(dú)立的內(nèi)存區(qū)域存儲(chǔ),簡單賦值字符串指針會(huì)使兩個(gè)對(duì)象的指針成員指向相同的地址,這就是淺拷貝,可能帶來內(nèi)存泄露。在拷貝賦值運(yùn)算符重載函數(shù)中要清理內(nèi)存,并且重新申請(qǐng)新的內(nèi)存空間,這就是深拷貝。
//拷貝賦值運(yùn)算符
String& operator=(const String& str)
{
m_data=s.m_data;//指針變量直接賦值,淺拷貝
}
2.2 拷貝賦值函數(shù)
必須注意的是拷貝賦值函數(shù)要檢測(cè)自我賦值,因?yàn)榭截愘x值函數(shù)的工作是,先釋放自身指針指向的內(nèi)存,再重新申請(qǐng)內(nèi)存,進(jìn)行賦值。自我賦值會(huì)先釋放自己的數(shù)據(jù)部分,在接下的步驟產(chǎn)生未定義行為。
String& operator=(const String& str)
{
if (this == &str) //防止自我賦值
return *this;
delete[] m_data;
m_data = new char[ strlen(str.m_data) + 1 ];
strcpy(m_data, str.m_data);
return *this;
}
2.3 析構(gòu)函數(shù)
先析構(gòu),析構(gòu)對(duì)象,再進(jìn)入函數(shù)體
~String() //第一步析構(gòu)對(duì)象
{
delete[] m_data;//第二步進(jìn)入函數(shù)體,釋放指針指向的內(nèi)存空間
}
二、array new 和 array delete
我們?cè)谏蓴?shù)組和清理數(shù)組用到的就是array new 和 array delete
char* str=new char[12];//array new
delete[] str;//array delete
若是數(shù)組沒有采用array delete 將會(huì)產(chǎn)生內(nèi)存泄露。

數(shù)組在內(nèi)存上存儲(chǔ)上包括一個(gè)計(jì)數(shù)部分和數(shù)據(jù)部分,在圖中為3。沒有采用 array delete ,在析構(gòu)時(shí)只調(diào)用一次析構(gòu)函數(shù),所以另外兩個(gè)指針指向的內(nèi)存空間沒有得到釋放,造成了內(nèi)存泄露。
所以出乎意料的事,不帶指針的類生成的數(shù)組,不用 array delete 也不會(huì)造成了內(nèi)存泄露,但是對(duì)于每個(gè)程序員都要警惕這種錯(cuò)誤,每次 array new 都要采用 array delete。