成員初始化列表與構造函數體區別

C++ Primer中在講構造函數初始化列表的時候有這麼一段話: 
      無論是在構造函數初始化列表中初始化成員,還是在構造函數體中對它們賦值,最終結果是相同的。不同之處在於,使用構造函數初始化列表的版本表示初始化數據成員,沒有定義初始化列表的構造函數版本在構造函數體中對數據成員賦值。


首先把數據成員按類型分類 
1、內置數據類型,複合類型(指針,引用) 
2、用戶定義類型(類類型


對於類型1,在成員初始化列表和構造函數體內進行,在性能和結果上都是一樣的 
對於類型2,結果上相同,但是性能上存在很大的差別。因爲類類型的數據成員對象在進入函數體是已經構造完成,也就是說在成員初始化列表處進行構造對象的工作,這是調用一次構造函數,在進入函數體之後,進行的是對已經構造好的類對象的賦值,又調用個拷貝賦值操作符才能完成(如果並未提供,則使用編譯器提供的默認按成員賦值行爲)


雖然大多數情況下,這兩種初始化方式並沒有太大差別,但其實更推薦使用成員初始化列表,尤其是有一些情況下必要的,另一個原因是出於效率。


第一個原因——必要性。設想你有一個類成員,它本身是一個類或者結構,而且只有一個帶一個參數的構造函數。 
class CMember { 
 public: 
    CMember(int x) { ... } 
}; 
因爲Cmember有一個顯式聲明的構造函數,編譯器不產生一個缺省構造函數(不帶參數),所以沒有一個整數就無法創建Cmember的一個實例。 
CMember* pm = new CMember; // Error!! 
CMember* pm = new CMember(2); // OK 
如果Cmember是另一個類的成員,你怎樣初始化它呢?你必須使用成員初始化列表。 
class CMyClass { 
    CMember m_member; 
 public:
    CMyClass(); 
}; 
//必須使用成員初始化列表 
CMyClass::CMyClass() : m_member(2) 


第二個原因是出於效率考慮。編譯器總是確保所有成員對象在構造函數體執行之前初始化,因此會需要先調用成員的缺省構造函數,完成成員初始化之後再進入構造函數體中執行賦值操作。一般而言,重複的函數調用是浪費資源的,尤其是當構造函數和賦值操作符分配內存的時候。在一些大的類裏面,你可能擁有一個構造函數和一個賦值操作符都要調用同一個負責分配大量內存空間的Init函數。在這種情況下,你必須使用初始化列表,以避免不要的分配兩次內存。


考慮初始化列表的問題時,有一個特性需要注意,它是關於C++初始化類成員的,它們是按照聲明的順序初始化的,而不是按照出現在初始化列表中的順序。




class CMyClass { 
    CMyClass(int x, int y); 
    int m_x; int m_y; 
}; 
CMyClass::CMyClass(int i) : m_y(i), m_x(m_y) { } 
你可能以爲上面的代碼將會首先做m_y=I,然後做m_x=m_y,最後它們有相同的值。但是編譯器先初始化m_x,然後是m_y,,因爲它們是按這樣的順序聲明的。結果是m_x將有一個不可預測的值。

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