2020-12-14(全局/静态对象的构造函数和析构函数调用的时机以及地址)
一般的對象實例化在什么時候?qū)嵗哪?#xff1f;
是不是在main函數(shù)運行到那里的時候,然后創(chuàng)建對象,會調(diào)用類里面的構(gòu)造函數(shù)。
那當(dāng)我們遇到全局/靜態(tài)對象的時候,它是不是也是需要在main函數(shù)里面慢慢構(gòu)造呢?
答案是 :
不是的。
全局/靜態(tài)對象 的構(gòu)造函數(shù)調(diào)用實在main函數(shù)之前的。
有人在疑問?main函數(shù)之前還有函數(shù)?不是從main函數(shù)開始運行的嗎?
全局對象所在的內(nèi)存地址空間為全局?jǐn)?shù)據(jù)區(qū),而局部對象的內(nèi)存地址空間在棧中,他們觸發(fā)構(gòu)造函數(shù)和析構(gòu)函數(shù)時機(jī)不同。
全局/靜態(tài)對象構(gòu)造函數(shù)實現(xiàn):
在啟動函數(shù)mainCRTStartup中有個_cinit,全局對象的構(gòu)造函數(shù)就是在此函數(shù)中實現(xiàn)的,
在函數(shù)_cinit的_initterm函數(shù)調(diào)用中,初始化了全局對象。_initterm實現(xiàn)代碼片段如下:
當(dāng)pfbegin不為NULL時進(jìn)入if語句塊。執(zhí)行(**pfbegin)();
后并不會進(jìn)入全局對象的構(gòu)造函數(shù)中,而是進(jìn)入編譯器提供的構(gòu)造代理函數(shù)中,由一個負(fù)責(zé)全局對象的構(gòu)造代理函數(shù)完成對全局構(gòu)造函數(shù)的調(diào)用過程。
構(gòu)造代理函數(shù)代碼如下:
由于構(gòu)造函數(shù)需要傳遞對象的首地址作為this指針,而且構(gòu)造函數(shù)可以帶各類參數(shù),因此編譯器將為每個全局對象生成一段傳遞this指針和參數(shù)的代碼,然后使用無參的代理函數(shù)去調(diào)用構(gòu)造函數(shù)。
全局/靜態(tài)對象析構(gòu)函數(shù)實現(xiàn):
全局/靜態(tài)對象相同,其構(gòu)造函數(shù)在函數(shù)_cinit的第二個_initterm調(diào)用中被構(gòu)造。他們的析構(gòu)函數(shù)的調(diào)用時機(jī)是在main函數(shù)執(zhí)行完畢之后。既然構(gòu)造函數(shù)出現(xiàn)在初始化過程中,對應(yīng)的析構(gòu)函數(shù)就會出現(xiàn)在程序結(jié)束出。我們來看一下mainCRTStartup函數(shù),它在調(diào)用main函數(shù)結(jié)束后使用了exit用來終止程序,如下:
在main函數(shù)調(diào)用結(jié)束后,由exit來結(jié)束進(jìn)程,從而終止程序的運行。全局對象的析構(gòu)函數(shù)的調(diào)用也在其中,由exit函數(shù)內(nèi)的doexit實現(xiàn),關(guān)鍵代碼如下:
if(_onexitbegin)//_onexitbegin為函數(shù)指針數(shù)組的首地址 { _PVFV * pfend=_onexitend; //__onexitbegin為函數(shù)指針數(shù)組的尾地址 while(--pend >=__onexitbegin)//從后向前依次釋放全局對象if(*pend!=NULL)(**pend)();//調(diào)用數(shù)組中保存的函數(shù) }__onexitbegin指向一個指向數(shù)組,該數(shù)組中保存著各類資源釋放時的函數(shù)的首地址。編譯器實在何時生成這樣一個數(shù)組的呢?
全局構(gòu)造函數(shù)的調(diào)用是在_cinit函數(shù)的第二個_initterm函數(shù)內(nèi)完成,而在第二個_initterm函數(shù)的初始化函數(shù)指針數(shù)組。在執(zhí)行每個全局對象構(gòu)造代理函數(shù)時都會執(zhí)行對象的構(gòu)造函數(shù),然后使用atexit注冊析構(gòu)代理函數(shù)。
舉例:
如果定義一個全局對象CMyString G_MyStringTwo;,該對象的全局析構(gòu)函數(shù)代理函數(shù)的分析如下所示:
;該代理函數(shù)由編譯器添加,無源碼對照
;函數(shù)入口對照
由于函數(shù)數(shù)組中保存的析構(gòu)代理函數(shù)被定義為無參函數(shù),因此在調(diào)用析構(gòu)函數(shù)時無法傳遞this指針。于是編譯器需要為每個全局變量和靜態(tài)對象建立一個中間代理的析構(gòu)函數(shù),用于傳入全局對象的this指針。
總結(jié)
以上是生活随笔為你收集整理的2020-12-14(全局/静态对象的构造函数和析构函数调用的时机以及地址)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++对象长度之空类(1)
- 下一篇: c++对象长度之静态数据成员(3)