所謂static對象,其壽命從被構造出來直到程序結束爲止,因此
stack和heap-based對象都被排除。這種對象包括global對象,定
義於namespace作用域內的對象、在class內、在函數內、以及在
file作用域內被聲明爲static的對象。函數內的static對象稱爲
local static對象(因爲它們對函數而言是local),其他static
對象稱爲non-local static對象。程序結束時static對象會被自動
銷燬,也就是它們的析構函數會在main()結束時被自動調用。
所謂編譯單元(translation unit)是指產出單一目標文件
(single object file)的那些源碼。基本上它是單一源碼文件加
上其所含入的頭文件。
C++對“定義於不同編譯單元內的non-local static對象”的初始
化次序並無明確定義。
問題來了:如果某編譯單元內的某個non-local static對象的初始
化動作使用了另一個編譯單元內的某個non-local static對象,它
所用到的這個對象可能尚未被初始化。
解決方法:
將每個non-local static對象搬到自己的專屬函數內(該對象在此
函數內被聲明爲static)。這些函數返回一個reference指向它所
含的對象。然後用戶調用這些函數,而不直接指涉這些對象。這個
專屬函數我們叫它reference-returning函數。其形式大致爲:
class classNameA { ... }; class classNameB { ... inline classNameA& clsNameAObj() { static classNameA clsNameA; return clsNameA; } ... }
這個方法的基礎在於:C++保證,函數內的local static對象會在
“該函數被調用期間”“首次遇上該對象之定義式”時被初始化。
但從另一個角度看,這些函數“內含static對象”的事實使他們在
多線程系統中帶有不確定性。我們可以在程序的單線程啓動階段手
工調用所有reference-returning函數,這可消除與初始化有關的
“競速形式(race conditions)”。
我們總是需要爲內置型對象進行手工初始化,因爲C++不保證初始化他們。