《C++ Effective》條款4:確定物件被使用前已被初始化
本條款主要講解了類成員初始化的問題;
本章的宗旨旨在初始化類成員,保證類成員能夠成功初始化,防止未初始化造成使用之外的錯誤;
初始化列表:
作者希望人們使用初始化列表而建構函式體內賦值的方式進行初始化的定義;
class test { private: int a; string s; double b; public: test(const int& a,const string& s,const double& b):a(a),b(b),s(s){} };
如上所示,使用初始化列表定義可以有效避免開銷;
如果採用建構函式體內進行賦值,則會出現先default構造,再賦值的問題;
而如果直接使用初始化列表方式來進行構建,則只用賦值一次,直接default構造;
同時,值得注意的是初始化的順序,有兩大原則:
1.基類優先於派生類進行初始化;
2.對於類內成員,優化順序和初始化值表的順序相同
所以需要謹慎的是初始化值表順序的構造,順序不同可能會影響初始化的預期;
class test { private: int a; string s; double b; string ss; public: test(const int& a,const string& s,const double& b):a(a),b(b),s(s),ss(s+'2'){} };
正如該例子所示,ss和s的初值隨著初始化值列表的不同而可能出現二義性;
關於static物件的初始化問題:
這裡需要注意一下static物件和static關鍵字的區別;
首先注意一下static物件的定義:指global物件、用於namespace作用域內的物件,以及classes內、函式內、以及再file作用域內宣告為static的物件;
首先static物件可以分為兩大部分:
1.local-static物件:函式內的使用static宣告的物件;
2.non-local-static物件:除了在函式內使用static宣告的其他static物件;
對於static物件,存在問題的是呼叫鏈問題,也就是對於多個檔案內的初始化順序問題;
例如:A,B兩個類,A是B的類內元素,所以一般需要先初始化B中的A,再初始化B,但是並不能確保這樣的順序;
問題根源:C++只保證了單類中的構造順序,對於多個類的呼叫鏈不能保證初始化的先後;
解決方案:使用local-static物件來進行解決:
使用函式返回static物件,來進行local-static物件構造;
class FileSystem{ private: int value; public: FileSystem() :value(0) {}; int rv() { return value; } }; class Directory { public: Directory() { int x = tfs().rv(); } }; FileSystem& tfs() { static FileSystem fs; return fs; } Directory& tempDir() { static Directory td; return td; }
通過函式返回local-static物件,可以再返回的時候完成物件的構造,從而不用關心是多個類初始化構造的問題;
該種技術稱之為reference-returning,後續也會有更多的章節詳細介紹多執行緒下的static物件技術,因為多執行緒中極易引起混亂;
存在問題:
1.static關鍵字複習;
2.關於local-static生命週期的問題;
3.引用和指標的詳細歸類;
4.extern宣告的問題;