在C++中,關於對象的初始化動做什麼時候必定發生,什麼時候不必定發生這個問題,最佳的處理辦法就是:永遠在使用對象以前先將它初始化。安全
關於在構造函數中初始化,重要的一點是不要混淆了賦值和初始化。函數
class PhoneNumber { ... }; class ABEntry { private: std::string theName; std::string theAddress; std::list<PhoneNumber> thePhones; int numTimesConsulted; public: ABEntry{const std::string &name, const std::string &address, const std::list<PhoneNumber> &phones}; }; /* 正確可行但不是最好的方法:在構造函數體內對成員變量進行賦值 */ ABEntry::ABEntry{const std::string &name, const std::string &address, const std::list<PhoneNumber> &phones} { theName = name; //theName、theAddress、thePhones都是賦值, theAddress = address; //而不是初始化。 thePhones = phones; numTimesConsulted = 0; } /* 較好的方法:使用初始化列表對成員變量進行初始化 */ ABEntry::ABEntry{const std::string &name, const std::string &address, const std::list<PhoneNumber> &phones} :theName(name), theAddress(address), thePhones(phones), numTimesConsulted(0) //爲了一致性,內置類型對象初始化最好也在初始化列表中進行 { }
對大多數類型而言,比起先調用default構造函數而後再調用operator =,單隻調用一次copy構造函數是比較高效的,有時甚至高效得多。
而對於內置類型對象如numTimesConsulted,其初始化和賦值的成本是同樣的,但爲了一致性最好也經過初始化列表來初始化。線程
若是成員變量是const或reference,那麼不論是內置類型仍是自定義類型,都必定須要初值,不能被賦值,都只能經過初始化列表進行初始化(見條款5)。
爲避免須要記住什麼時候必須使用初始化列表,什麼時候不須要,最簡單的作法就是:設計
可是,一些class有多個構造函數,並且有許多成員變量和/或base class,若是每一個構造函數都使用初始化列表,那麼就會形成大量的代碼重複。
這種狀況下,能夠合理地對"賦值和初始化開銷同樣"的成員變量改用賦值操做,並將這些賦值操做封裝到一個private init函數中,供全部構造函數調用。
這種作法在"成員變量的初始值來自於文件或數據庫讀入"時特別有用。然而,比起經由賦值操做完成的"僞初始化",經過初始化列表完成的"真正初始化"一般更加可取。code
C++在單個對象建立時有着十分固定的成員初始化順序,口訣就是"先父母,再客人,後本身"。對象
若是已經在初始化列表中對base class和全部成員變量進行了初始化,那就只剩下一個問題——"不一樣源文件內定義的non-local static對象"的初始化問題。
先來明確下概念,函數內定義的static對象稱爲local static對象,其餘地方定義的static對象稱爲non-local static對象。
如今,咱們關心的問題涉及至少兩個源文件,每一個源文件中都至少含有一個non-local static對象,所以可能發生以下問題。string
產生該問題的緣由是C++對不一樣源文件中的non-local static對象初始化順序沒有明肯定義,幸運的是經過一個小小的設計即可徹底消除該問題,惟一須要作的是:it
該方法其實是用local static對象替換了non-local static對象,這也是Singleton模式的一個常見實現手法。該方法之因此管用,是由於:編譯
能夠看到,這種結構下的函數體每每十分簡單固定:第一行定義並初始化一個local static對象,第二行返回一個引用指向它。
這使得它們很是適合實現爲inline函數,尤爲是須要被頻繁調用的場合;但從另外一個角度看,內含static對象也使得它們成爲線程不安全函數。
class FileSystem { ... }; //static FileSystem tfs; //FileSystem.cpp中定義的non-local static對象 //tfs的專屬函數,用來替換tfs對象 FileSystem &tfs() { static FileSystem fs; //定義並初始化一個local static對象fs return fs; //返回一個reference指向上述對象 }
class Directory { ... }; Directory::Directory() { //... std::size_t disks = tfs().numDisks(); //... } //static Directory tempDir; //Directory.cpp中定義的non-local static對象,tempDir的初始化依賴於FileSystem.cpp中的tfs對象先初始化完成 //tempDir的專屬函數,用來替換tempDir對象 Directory &tempDir() { static Directory td; //定義並初始化一個local static對象td return td; //返回一個reference指向上述對象 }