使用静态全局对象自动做初始化与清理工作

在程序开发中,往往要在程序启动或模块被加载时,需要做一些初始化的工作(例如:资源加载、内存创建、变量初始化或执行函数[脚本]等);

而在程序结束或模块被卸载时,需要做一些清理的工作(例如:资源回收、内存释放、状态清理或执行函数[脚本]等)。

+++++++++++++++++++++++++++++++++++++

首先,我们使用下面例子,来测试下静态全局对象exedll中的构造和析构时机。

整个程序结构如下:

DllTest.dll动态连接库测试代码:

 1 #include "stdafx.h"
 2 #include "dllTest.h"
 3 #include <cstdio>
 4 
 5 BOOL APIENTRY DllMain( HANDLE hModule, 
 6                        DWORD  ul_reason_for_call, 
 7                        LPVOID lpReserved
 8                      )
 9 {
10     switch (ul_reason_for_call)
11     {
12         case DLL_PROCESS_ATTACH:
13             {
14                 printf("DLL: DLL_PROCESS_ATTACH\n");
15             }
16             break;
17         case DLL_THREAD_ATTACH:
18             {
19                 printf("DLL: DLL_THREAD_ATTACH\n");
20             }
21             break;
22         case DLL_THREAD_DETACH:
23             {
24                 printf("DLL: DLL_THREAD_DETACH\n");
25             }
26             break;
27         case DLL_PROCESS_DETACH:
28             {
29                 printf("DLL: DLL_PROCESS_DETACH\n");
30             }
31             break;
32         default:
33             {
34                 printf("DLL: DEFAULT\n");
35             }
36             break;
37     }
38     return TRUE;
39 }
40 
41 
42 
43 44 static class CFirstLoader 45 { 46 public: 47 CFirstLoader() 48 { 49 printf("DLL: CFirstLoader Construct\n"); 50 } 51 ~CFirstLoader() 52 { 53 printf("DLL: CFirstLoader Destruct\n"); 54 } 55 } s_firstLoader; 56 57 static class CSecondLoader 58 { 59 public: 60 CSecondLoader() 61 { 62 printf("DLL: CSecondLoader Construct\n"); 63 } 64 ~CSecondLoader() 65 { 66 printf("DLL: CSecondLoader Destruct\n"); 67 } 68 } s_secondLoader;

ConsoleTest.exe主程序测试代码:

 1 #include "stdafx.h"
 2 
 3 static class CFirstLoader
 4 {
 5 public:
 6     CFirstLoader()
 7     {
 8         printf("EXE: CFirstLoader Construct\n");
 9     }
10     ~CFirstLoader()
11     {
12         printf("EXE: CFirstLoader Destruct\n");
13     }
14 } s_firstLoader;
15 
16 static class CSecondLoader
17 {
18 public:
19     CSecondLoader()
20     {
21         printf("EXE: CSecondLoader Construct\n");
22     }
23     ~CSecondLoader()
24     {
25         printf("EXE: CSecondLoader Destruct\n");
26     }
27 } s_secondLoader;
28 
29 int main(int argc, char* argv[])
30 {
31     printf("EXE: main\n");
32 
33     printf("EXE: Call LoadLibrary\n");
34     HINSTANCE hDll = LoadLibrary("dllTest.dll");
35 
36     if (NULL != hDll)
37     {
38         printf("EXE: Call FreeLibrary\n");
39         FreeLibrary(hDll);
40     }
41 
42     return 0;
43 }

程序输出来的调用日志:

EXE: CFirstLoader Construct
EXE: CSecondLoader Construct
EXE: main
EXE: Call LoadLibrary
DLL: CFirstLoader Construct
DLL: CSecondLoader Construct
DLL: DLL_PROCESS_ATTACH
EXE: Call FreeLibrary
DLL: DLL_PROCESS_DETACH
DLL: CSecondLoader Destruct
DLL: CFirstLoader Destruct
EXE: CSecondLoader Destruct
EXE: CFirstLoader Destruct

通过分析日志,我们可以得到如下结论:

1. EXE中的静态全局对象的构造在main函数调用之前,析构在main函数调用之后。

2. DLL中的静态全局对象的构造在DLL_PROCESS_ATTACH之前,析构在DLL_PROCESS_DETACH之后。

3. EXE与DLL中的静态全局对象的构造顺序定义的先后顺序保持一致,析构顺序则正好相反

利用这一点,我们可以在static CFirstLoader s_firstLoader的构造与析构行为,来自动地进行初始化和清理工作。

这样做的好处是:无需外部显示调用来完成,程序简洁,非常cool!

原文地址:https://www.cnblogs.com/kekec/p/2786143.html