深度剖析C 全域性建構函式和析構函式的呼叫機制

2021-06-05 20:35:13 字數 1232 閱讀 7288

c++全域性建構函式和析構函式的呼叫機制

控制台exe中c++的全域性變數在main之前初始化,在main之後清除,vc編譯器、鏈結器和vc執行庫**互相配合完成了這個魔術。請複製這段**到你新建的控制台程式,建立並執行:

#include "stdafx.h"

#include

#define secname ".crt$xcu"

#pragma section (secname, long, read)

void cleanup()

void init()

typedef void (_cdecl *_pvfv) () ;

_declspec (allocate(secname)) _pvfv callb4main = ;

int main()

輸出結果:

hello

in main

bye

奇怪!你並沒有呼叫init和cleanup,但很明顯它們被呼叫了,這是怎麼回事呢?

我們知道真正的入口函式是maincrtstartup,對於我們的討論,maincrtstartup可簡化如下:

int __tmaincrtstartup()//這個函式會被鏈結進我們的exe,並作為入口點函式

//  file:   crt\src\crt0dat.c

static void _cdecl _initterm  (_pvfv * pfbegin,_pvfv * pfend)

}

這就是呼叫建構函式的地方。對於我們定義的每乙個全域性變數,編譯器把它的構造函式呼叫(不管你帶多少引數)編譯成一段**(簽名格式為_pvfv),這段**同時用atexit註冊了析構函式(對於編譯器這是很容易的)。然後把這段**的函式指標放入乙個_pvfv陣列。鏈結器把這些_pvfv陣列連成乙個大陣列。

_initterm引數中的pfbegin就指向這個陣列的第乙個元素,pfend指向這個陣列的最後乙個元素(總為null),我們的建構函式就這樣被呼叫了,這也是上面的魔術的工作原理。atexit註冊的函式將在main之後exit(與_initterm**相似)中執行,而且遵循lifo的原則,所以析構函式會按照和建構函式相反的順序呼叫。

對於非控制台exe和dll,情形是類似的。

任何使用者態程序的真正的入口其實是kernel32.dll!_baseprocessstart@4,但這與我們的討論無關。

《程式設計師的自我修養--裝載、鏈結和庫》

C 全域性物件構造和析構

注 此為小白引導教程 引入 c 中的全域性物件什麼時候執行建構函式?什麼時候執行析構函式?與區域性物件又有什麼區別?正文 思路是這樣的,我們先寫乙個類,乙個有點簡單 又不簡單 的類 include include using std string using std cout using std e...

深度剖析空間配置器(一)構造和析構函式

頻繁的申請和釋放,就會頻繁的呼叫malloc函式和free函式 呼叫函式會壓棧出棧,這些都是有開銷的 這就會造成,即使是有足夠的記憶體 40位元組 但是通過申請並不能得到乙個連續24位元組的記憶體 從而引入了空間配置器 空間介面卡是stl,標準模板庫的六大元件之一,其餘分別是 容器,迭代器,演算法,...

C 的全域性構造與析構函式

我們知道一般的c c 的程式是從main函式開始的,然後在main函式結束後程式結束。但是不然,在main函式開始執行前,已經有其他的指令被執行了。為了程式的順利執行,首先要初始化執行環境,比如堆分配初始化 malloc,free 執行緒子系統等,這裡先提一下 c 的全域性物件建構函式就是在這一時期...