C++中全局變量的初始化全過程
C++全局變量的初始化過程
全局變量在main()前完成初始化(調(diào)用構(gòu)造函數(shù))
在調(diào)用構(gòu)造函數(shù)前,全局變量已分配空間,內(nèi)存全0
多個全局變量的初始化,按照代碼編譯的順序
注意:全局變量被訪問前可能它還沒有調(diào)用構(gòu)造函數(shù)初始化。
如果一個項目中,多個dll都用到一個全局變量在共同的lib中,則每個dll都有一個獨立的全局變量(地址不同),每個全局變量會初始化。
如下代碼,A里面訪問了全局變量g_b, 改變?nèi)肿兞縢_a,g_b的順序 會導(dǎo)致g_b.b的輸出結(jié)果不同。
如按照A g_a; B g_b 的順序定義,編譯器會先調(diào)用A()時,這時g_b還沒有調(diào)用B(), g_b.b=0,然后賦值 g_b.b=101;
然后調(diào)用B(),g_b.b的值被改成1.
#include <istream> using namespace std; class B { public: int b = 1; }; extern B g_b; class A { public: int a = 0; A() { g_b.b = 101; } }; #if 0 B g_b; A g_a; #else A g_a; B g_b; #endif int main() { printf("g_b=%d\n", g_b); //AB: g_b=1; BA: g_b=101 return 0; }
C++全局變量初始化的順序
雖然一直強調(diào)不要用全局變量。但是對于特殊的應(yīng)用場合,還是有全局變量的使用(如某些多進程、多線程的共享資源),我們希望在首次運行(載入)時,系統(tǒng)能夠幫助我們進行一些必要的初始化。
If a program starts a thread (30.3), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit. If a program starts a thread, the subsequent unordered initialization of a variable is unsequenced with respect to every other dynamic initialization. Otherwise, the unordered initialization of a variable is indeterminately sequenced with respect to every other dynamic initialization
對不同的源文件中的全局變量,標準C++對全局變量初始化的順序并沒有要求。對于同一個原文件中,全局變量按照定義先后順序初始化。
對于堆類型的全局變量的創(chuàng)建和構(gòu)造,可能在一個構(gòu)造函數(shù)中調(diào)用另一個未構(gòu)造的全局變量,通常會檢查另一個指針是否有效,并在無效時構(gòu)造那個對象。這就出現(xiàn)一個問題:
一個指針在構(gòu)造之前,被初始化。c/c++運行時,仍然會再次構(gòu)造那個指針(全局變量為空指針)。
這會引發(fā)資源泄露,甚至運行時錯誤。
解決措施。雖然按需創(chuàng)建是一種很好的思路。但是必須符合c/c++運行機制。解決方式就是不使用堆創(chuàng)建對象,而是使用棧內(nèi)存對象(c++內(nèi)部大使用致雙檢查鎖的方式保證構(gòu)造一次)。我們也可以自己實現(xiàn)雙檢查鎖的思路,但是我們使用的鎖的創(chuàng)建過程,本身就是需要雙檢查鎖定的,這是自相矛盾的。
參考C++標準具體介紹:(原文:Storage class specifiers - cppreference.com)
Variables declared at block scope with the specifier static or thread_local (since C++11) have static or thread (since C++11) storage duration but are initialized the first time control passes through their declaration (unless their initialization is zero- or constant-initialization, which can be performed before the block is first entered). On all further calls, the declaration is skipped.
If the initialization throws an exception, the variable is not considered to be initialized, and initialization will be attempted again the next time control passes through the declaration.
If the initialization recursively enters the block in which the variable is being initialized, the behavior is undefined.
If multiple threads attempt to initialize the same static local variable concurrently, the initialization occurs exactly once (similar behavior can be obtained for arbitrary functions with std::call_once).
Note: usual implementations of this feature use variants of the double-checked locking pattern, which reduces runtime overhead for already-initialized local statics to a single non-atomic boolean comparison.
(since C++11) The destructor for a block-scope static variable is called at program exit, but only if the initialization took place successfully.
Function-local static objects in all definitions of the same inline function (which may be impli
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
C語言中g(shù)etch()函數(shù)詳解及簡單實例
這篇文章主要介紹了C語言中g(shù)etch()函數(shù)詳解及簡單實例的相關(guān)資料,需要的朋友可以參考下2017-03-03