Effective C++學記之04 確定對象被使用前先被初始化

1 對內置類型進行手工初始化,因爲c++不保證初始化它們。
內置類型:int x = 0; //手工實現初始化

通常如果使用c part of c++而且初始化可能招致運行期成本,就不保證發生初始化;
一旦進入non-c part of c++,規則有些變化。這就很好的解釋了爲甚array(來自c part of c++)不保證其內容初始化,而vector(來自non-c part of c++)卻有次保證。

2 構造函數最好使用成員初值列,而不要在構造函數本體內使用複製操作。初值列列出的成員變量,其排列次序應該和他們在class中的聲明次序相同。

看下面這個例子:

class ADEntry{
public:
    ABEntry(const std:string& name);
private:
    std::string theName;
};
ABEntry::ABEntry(const std:string& name)
{
    theName = name;//這是賦值,不是初始化!!
}
c++規定,對象的成員變量的初始化動作發生在進入構造函數本體之前。也就是各個成員的default構造函數被自動調用之時(內置類型除外)。以上代碼首先調用default構造函數爲theName設初值,然後立即再對theName賦予新值。default構造函數的一切作爲因此浪費了。

更高效的寫法:使用成員初值列(member initialization  list)替換賦值動作。如下:
ABEntry::ABEntry(const std::string& name):theName(name){//構造函數內不必有任何操作}

初值列中針對各個成員變量設置的實參,被拿去作爲各成員變量之構造函數的實參。本例中theName以name爲初值進行copy構造。

對於大多數類型而言,比起先調用default構造函數再調用copy賦值操作符,只調一次copy構造函數是比較高效的;對於內置對象,其初始化和賦值的成本相同,但爲了一致性最好也通過成員初值列來初始化。


BAEntry::BAEntry():theName(),    //調用theName的default構造函數
           numTimesConsulted(0) //將numTimesConsulted顯式初始化爲0
{}

規則:總是在初值列中列出所有成員變量,以免還得記住哪些成員變量可以無需初值。
注意:如果成員變量是const或者引用,必須初始化,不能被賦值。(條款5)
對於擁有多個構造函數的class且存在多個成員變量或base class,可以合理地在初值列遺漏哪些“賦值表現像初始化一樣好”的成員變量。

3 爲免除“跨編譯單元之初始化次序”問題,請以local static對象替換non-local static對象。

這裏說的local static對象指的是函數內的static對象。相應的其他static對象就被稱爲non-local static對象。
所謂編譯單元是說產出單一目標文件的源碼(源碼文件+頭文件 #include files)。
由於c++對“不同編譯單元內定義之non-local static對象”的初始化次序沒有明確定義。
如果某編譯單元內的某個non-local static對象的初始化操作使用了另一個編譯單元內的某個non-local static對象,這個對象可能尚未被初始化。

解決的辦法就是:將non-local static對象變爲local static對象。將每個non-local static函數搬到自己的專屬函數內(該對象在此函數內被聲明爲static),這些函數返回一個引用指向它所含的對象。然後調用這個函數,而不直接指涉這些對象。
(例:單例模式的實現)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章