條款04 確定物件被使用前已先被初始化

2021-09-21 17:34:11 字數 2969 閱讀 9378

最佳的處理方法:永遠在使用物件的之前先將他初始化,對於無任何成員的內建型別,你必須手工完成此時;對於內建型別以外的任何其他東西,初始化責任落在建構函式身上:確保每乙個建構函式都將對物件的每乙個成員初始化。

但是別混淆賦值(assignment)和初始化(initialization)。

//內建型別如下

int x = 0; //對int進行手工初始化

const char* text = "a c-style string"; //對指標進行手工初始化

double d;

std::cin >> d; //以讀取input stream的方式完成初始化

//非內建型別如下

class phonenumber;

class abentry //abentry = "address book entry"

;abentry::abentry(const std::string& name,const std::string address,

const std::list& phones)

abentry的建構函式的乙個較佳的寫法是使用所以的member initialization list(成員初始化)替代賦值操作。這樣做的和上述最終結果一樣,但是通常效率更高:

abentry::abentry(const std::string& name,const std::string address,

const std::list& phones):

thename(name), //這些是初始化

theaddress(address),

thephone(phones),

numtimesconsulted(0)

對大多數型別而言,先呼叫default建構函式然後再呼叫copy assignment操作符,單隻呼叫一次copy構造是比較高效的,有時候高效很多。

規定:總是在成員初始化列表中列出所有成員,以免還的記住哪些成員變數可以無需初始化。例如,由於numtimesconsulted屬於內建型別,如果成員初始化列表(member initialization list)遺漏了它,他就沒初值,因而可能開啟不明確行為。

有時候即使面對的成員變數屬於內建型別(那麼其初始化和賦值得到成本相同),也一定的使用成員初始化列表:const或references。所以總是使用成員初始化列表,這樣做有時候絕對必要,而且往往比賦值搞笑。

c++有著十分固定的「成員初始化次序」。次序總是相同的:base classes更早於其derived classes被初始化,而class的成員變數總是以其宣告次序被初始化。為了不必要的錯誤,當你的成員初始化列表中列出各個成員時候,最好總是以其宣告次序為次序。

對於static物件而言,其壽命從被構造出來知道程式結束為止。這種物件包括global物件,定義於namespace作用域內的物件,在classes內、在函式內、以及file作用域內被宣告為static的物件。函式內的static物件稱為local static物件,其他的static物件稱為non-local static物件。程式結束時static物件被自動銷毀,也就是它們的析構會在main結束時自動呼叫。

現在關心的問題:設計至少兩個原始碼檔案,每乙個內含至少乙個non-local static物件,如果某個編譯單元內的某個non-local static物件的初始化動作使用了另乙個編譯單元內的某個non-local static物件,它所用到的這個物件可能尚未被初始化。因為c++對「定義於不同編譯單元內的non-local static物件」的初始化次序無明確定義。

如下假如你有乙個filesystem class,它讓網際網路上的檔案看起來像位於本機(local)。由於這個class,可能會產生乙個特殊物件,位於global或namespace作用域內,象徵單一檔案系統:

//程式庫

class filesystem //來自你的程式庫

;extern filesystem tfs; //預備給客戶使用的物件,tfs代表「the file system」

//客戶**

class directory //由程式庫客戶建立

;directory::directory(params)

directory tempdir(params); //為臨時檔案而做出的目錄

現在,初始化順序的重要性出來了:除非tfs在tempdir之前先被初始化,某則tempdir的建構函式會用到尚未初始化的tfs。但tfs和tempdir是不同的人在不同的時間於不同的原始碼建立起來的,它們定義於不同的編譯單元內的non-local static物件,你無法確定tfs會在tempdir之前被初始化。

對於這種問題,唯一要做的是:將每個non-local static物件搬到自己的專屬物件內(該函式被宣告為static)。這些函式返回乙個reference指向它所含的物件,然後使用者直接呼叫這些函式。這就是singleton設計模式。

這個手法的基礎在於:c++保證,函式內的local static物件會在「該函式被呼叫期間」「首次遇上該物件定義式」時被初始化。用此技術施行於tfs和tempdir身上,結果如下:

class filesystem;

filesystem& tfs() //這個函式用來替代tfs物件

class directory;

directory::directory(params)

directory& tempdir() //用這個函式替代tempdir物件

這種結構下的reference-returning函式往往十分單純:第一行定義並初始化乙個local static物件,第二行返回它。這種可以成為絕佳的inline候選人,尤其被頻繁呼叫。但從另外一給角度看,這些函式內含static物件,它們在多執行緒中帶有不確定性。處理這種麻煩的方法一種做法:在程式的單執行緒啟動階段手工呼叫所謂reference-returning函式,這可消除與初始化有關的條件競爭。

條款04 確定物件被使用前已先被初始化

總結 1.為內建型物件進行手工初始化,因為c 不保證初始化它們。2.建構函式最好使用成員初值列 memberinitialization list 而不要在建構函式本體內使用賦值操作 assignment 初值列列出的成員變數,其排列次序應該和它們在class中的宣告次序相同。3.為免除 跨編譯單元...

條款04 確定物件被使用前已先被初始化

讀取未初始化的值會導致不明確的行為,使程式終止或者行為不可 最佳的處理方法是 永遠在使用物件之前先將它初始化。在初始化時,有以下注意事項 對內建型別,需要手工完成初始化。對其他型別,確保建構函式都將物件的每乙個成員初始化。規定總是在初值列表中列出所有的成員變數,以免需要區分哪些成員變數無需初值。成員...

條款04 確定物件被使用前已先被初始化

條款04 確定物件被使用前已被初始化 include include include using std string using std cout using std endl using std list class point04 1.不要混淆了賦值 assignment 和初始化 initi...