Item11--如果class內動態置有記憶體,請為此class聲明一個copy constructor和一個assignment運算子
也就是說,class內有一個指標,使用new來動態申請記憶體的情況下,預設的copy constructor和assignment運算子是淺拷貝(bitwise copy),也即直接拷貝指標的值,可能會有記憶體泄露的危險
String a("hello");{String b("hello");b=a;}當b=a,b原來的內容變成野指標,當b結束範圍後a的內容也被刪除。這真是災難
所以條款11告訴我們:class內有指標需要申請記憶體,則自己撰寫拷貝構造和賦值函數,避免記憶體泄露和異常。
Item 12 -- 在constructor中盡量以initialization動作取代assignment動作
原因:
1,const、reference只能通過初始化列表進行初始化
2,從效率角度。對象的構造分成兩階段:初始化data member(可以根據初始化列表進行,無則初始化為0等預設值),執行被調用的建構函式。所以執行assignment實際執行了兩次賦值。
3,基本類型的non-const, non-reference對象,初始化和賦值之間沒有2所說的區別
Item 13 -- initialization中的members初始化次序應該和其在class內的聲明次序相同
原因也很容易理解:編譯器構造和析構的順序是相反的,編譯器不可能針對初始化列表中的順序進行初始化,否則重載不同初始化順序的建構函式會讓編譯器頭暈的。編譯器內部確定是按照class內的聲明次序,如果初始化列表不同,很可能初始化列表的資料會錯誤。
核心:先按class內聲明成員預設賦值,然後調用初始化參數列表進行初始化。
Item 14 -- 總是讓base class擁有virtual destructor
原因很容易理解:基類指標指向具體衍生類別,delete基類指標的時候,需要虛函數進行多態。
小tip:如果解構函式不是虛的,那麼基類和衍生類別的析構都要調用
,先調用派生,再調用基類
tip2:虛函數要佔用class空間,要綜合考量
Item 15 -- 令operator= 傳回"*this的reference"
原因:objA = objB = objC這種連續的重載=號行為
e.g.
String& String::operator =(const String&rhs) { … return *this; } |
Item16-- 在operator=中為所有的data members設定(賦值)內容
原因:編譯器會預設為你產生一個operator=,採用bitwise,所以最好都是自己寫一個
注意點:繼承機制的引入,Base中的私人成員Derived對象無法訪問
要麼 Base::operator=(rhs),要麼staqtic_cast<Base&>(*this) = rhs兩種方式解決
Item17 -- 在Operator=中檢查是否"自己賦值給自己"
一般採用的方法:
C& C::operator=(const C&rhs) { if(this==&rhs) return * this; } |
這主要是針對如何判斷對象相等的問題,這裡採用的是地址相等的方法