effective C++——第二章:構造、析構和賦值(item11~item17)

條款11: 爲需要動態分配內存的類聲明一個拷貝構造函數和一個賦值操作符

爲動態內存分配的類提供拷貝構造與賦值操作符,以避免使用缺省的拷貝構造與缺省賦值操作時由於類的成員變量間的內存拷貝造成程序crash。

拷貝構造函數和賦值運算符,官方的規則是:缺省拷貝構造函數(賦值運算符)對類的非靜態數據成員進行 “以成員爲單位的” 逐一拷貝構造(賦值)。即,如果m是類C中類型爲T的非靜態數據成員,並且C沒有聲明拷貝構造函數(賦值運算符),m將會通過類型T的拷貝構造函數(賦值運算符)被拷貝構造(賦值)—-如果T有拷貝構造函數(賦值運算符)的話。如果沒有,規則遞歸應用到m的數據成員,直至找到一個拷貝構造函數(賦值運算符)或固定類型(例如,int,double,指針,等)爲止。默認情況下,固定類型的對象拷貝構造(賦值)時是從源對象到目標對象的”逐位”拷貝。對於從別的類繼承而來的類來說,這條規則適用於繼承層次結構中的每一層,所以,用戶自定義的構造函數和賦值運算符無論在哪一層被聲明,都會被調用。具體例子,見 effective C++ 第七章:雜項

條款12: 儘量使用初始化而不要在構造函數裏賦值

1.因爲在構造函數中賦值之前,已經調用了類的成員變量的缺省構造函數將成員變量構造了一遍。這造成了效率的地下。
2.從純實際應用的角度來看,有些情況下必須用初始化。特別是const和引用數據成員只能用初始化,不能被賦值。

條款13: 初始化列表中成員列出的順序和它們在類中聲明的順序相同

必須保證初始化列表中成員列出的順序和它們在類中聲明的順序相同(類成員是按照它們在類裏被聲明的順序進行初始化的,和它們在成員初始化列表中列出的順序沒一點關係)
如果成員變量存在依賴關係,但是初始化列表順序寫反了,那麼會造成不可預期的結果。
class  Salary{
    Salary(int a):age(a),salary(age*1500){}
private:
    int salary;
    int age;
};

Salary s(55);//本意是salary = 55*1500,但實際不確定。因爲會先運算salary(age*1500),然後age纔會被賦值爲55。在此之前,age的值是不確定的。
(條款13:)實際上,如果你深究一下的話,會發現只是非靜態數據成員的初始化遵守以上規則。靜態數據成員的行爲有點象全局和名字空間對象,所以只會被初始化一次(詳見條款47)。另外,基類數據成員總是在派生類數據成員之前被初始化,所以使用繼承時,要把基類的初始化列在成員初始化列表的最前面。(如果使用多繼承,基類被初始化的順序和它們被派生類繼承的順序一致,它們在成員初始化列表中的順序會被忽略。使用多繼承有很多地方要考慮。

條款14: 確定基類有虛析構函數

確定基類有虛析構函數(爲了在使用多態的時候,所有資源能夠被正常的釋放(子類和基類的析構函數都會被調用,主要是爲了保證子類的析構被調用))
c++語言標準關於這個問題的闡述非常清楚:當通過基類的指針去刪除派生類的對象,而基類又沒有虛析構函數時,結果將是不可確定的。

條款15: 讓operator=返回*this的引用

讓operator=返回*this的引用(爲了讓operator=的返回值必須可以作爲另一個operator=的輸入參數,達到連續操作的目的)
c++程序員經常犯的一個錯誤是讓operator=返回void,這好象沒什麼不合理的,但它妨礙了連續(鏈式)賦值操作,所以不要這樣做。另一個常犯的錯誤是讓operator=返回一個const對象的引用

條款16: 在operator=中對所有數據成員賦值

條款17: 在operator=中檢查給自己賦值的情況

1.效率

  2.保證正確性。一個賦值運算符必須首先釋放掉一個對象的資源(去掉舊值),然後根據新值分配新的資源。在自己給自己賦值的情況下,釋放舊的資源將是災難性的,因爲在分配新的資源時會需要舊的資源。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章