C++中全局變量的初始化全過(guò)程
C++全局變量的初始化過(guò)程
全局變量在main()前完成初始化(調(diào)用構(gòu)造函數(shù))
在調(diào)用構(gòu)造函數(shù)前,全局變量已分配空間,內(nèi)存全0
多個(gè)全局變量的初始化,按照代碼編譯的順序
注意:全局變量被訪問(wèn)前可能它還沒(méi)有調(diào)用構(gòu)造函數(shù)初始化。
如果一個(gè)項(xiàng)目中,多個(gè)dll都用到一個(gè)全局變量在共同的lib中,則每個(gè)dll都有一個(gè)獨(dú)立的全局變量(地址不同),每個(gè)全局變量會(huì)初始化。
如下代碼,A里面訪問(wèn)了全局變量g_b, 改變?nèi)肿兞縢_a,g_b的順序 會(huì)導(dǎo)致g_b.b的輸出結(jié)果不同。
如按照A g_a; B g_b 的順序定義,編譯器會(huì)先調(diào)用A()時(shí),這時(shí)g_b還沒(méi)有調(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++全局變量初始化的順序
雖然一直強(qiáng)調(diào)不要用全局變量。但是對(duì)于特殊的應(yīng)用場(chǎng)合,還是有全局變量的使用(如某些多進(jìn)程、多線(xiàn)程的共享資源),我們希望在首次運(yùn)行(載入)時(shí),系統(tǒng)能夠幫助我們進(jìn)行一些必要的初始化。
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
對(duì)不同的源文件中的全局變量,標(biāo)準(zhǔn)C++對(duì)全局變量初始化的順序并沒(méi)有要求。對(duì)于同一個(gè)原文件中,全局變量按照定義先后順序初始化。
對(duì)于堆類(lèi)型的全局變量的創(chuàng)建和構(gòu)造,可能在一個(gè)構(gòu)造函數(shù)中調(diào)用另一個(gè)未構(gòu)造的全局變量,通常會(huì)檢查另一個(gè)指針是否有效,并在無(wú)效時(shí)構(gòu)造那個(gè)對(duì)象。這就出現(xiàn)一個(gè)問(wèn)題:
一個(gè)指針在構(gòu)造之前,被初始化。c/c++運(yùn)行時(shí),仍然會(huì)再次構(gòu)造那個(gè)指針(全局變量為空指針)。
這會(huì)引發(fā)資源泄露,甚至運(yùn)行時(shí)錯(cuò)誤。
解決措施。雖然按需創(chuàng)建是一種很好的思路。但是必須符合c/c++運(yùn)行機(jī)制。解決方式就是不使用堆創(chuàng)建對(duì)象,而是使用棧內(nèi)存對(duì)象(c++內(nèi)部大使用致雙檢查鎖的方式保證構(gòu)造一次)。我們也可以自己實(shí)現(xiàn)雙檢查鎖的思路,但是我們使用的鎖的創(chuàng)建過(guò)程,本身就是需要雙檢查鎖定的,這是自相矛盾的。
參考C++標(biāo)準(zhǔn)具體介紹:(原文: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é)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C++實(shí)現(xiàn)大整數(shù)乘法(字符串乘法)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)大整數(shù)乘法、字符串乘法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09C語(yǔ)言中g(shù)etch()函數(shù)詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了C語(yǔ)言中g(shù)etch()函數(shù)詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-03-03C++臨時(shí)性對(duì)象的生命周期詳細(xì)解析
臨時(shí)性對(duì)象的被摧毀,應(yīng)該是對(duì)完整表達(dá)式(full-expression)求值過(guò)程中的最后一個(gè)步驟。該完整表達(dá)式造成臨時(shí)對(duì)象的產(chǎn)生2013-09-09C語(yǔ)言實(shí)現(xiàn)六邊形掃雷游戲的示例代碼
所謂六邊形掃雷,就是沒(méi)有掃雷模式的消零算法,每一個(gè)安全的點(diǎn)都需要單獨(dú)挖出來(lái),一次顯示一個(gè)格子,感興趣的小伙伴可以跟隨小編一起了解一下2022-12-12C++標(biāo)準(zhǔn)模板庫(kù)STL深入講解
STL提供了一組表示容器、迭代器、函數(shù)對(duì)象和算法的模板。容器是一個(gè)與數(shù)組類(lèi)似的單元,可以存儲(chǔ)若干個(gè)值。STL容器是同質(zhì)的,即存儲(chǔ)的值的類(lèi)型相同:算法是完成特定任務(wù)(如對(duì)數(shù)組進(jìn)行排序或在鏈表中查找特定值)的處方2022-12-12