DLL中声明的全局变量会发生什么变化? < P> >我在C++中写了一个DLL,并声明了一个具有非平凡析构函数的类的全局对象。卸载DLL时是否会调用析构函数?

DLL中声明的全局变量会发生什么变化? < P> >我在C++中写了一个DLL,并声明了一个具有非平凡析构函数的类的全局对象。卸载DLL时是否会调用析构函数?,c++,windows,dll,C++,Windows,Dll,应在应用程序结束或卸载DLL时调用析构函数,以先到者为准。请注意,这在某种程度上取决于编译时所依据的实际运行时 此外,还要注意非平凡的析构函数,因为它同时存在计时和排序问题。在析构函数依赖的DLL之后,您的DLL可能会被卸载,这显然会导致问题。当调用DllMain with fdreason=DLL_PROCESS_DETACH参数时,表示应用程序卸载了DLL。这是调用全局/静态对象的析构函数之前的时间。来自Microsoft的此页将详细介绍全局对象的DLL初始化和销毁: 如果要查看链接.dll

应在应用程序结束或卸载DLL时调用析构函数,以先到者为准。请注意,这在某种程度上取决于编译时所依据的实际运行时


此外,还要注意非平凡的析构函数,因为它同时存在计时和排序问题。在析构函数依赖的DLL之后,您的DLL可能会被卸载,这显然会导致问题。

当调用DllMain with fdreason=DLL_PROCESS_DETACH参数时,表示应用程序卸载了DLL。这是调用全局/静态对象的析构函数之前的时间。

来自Microsoft的此页将详细介绍全局对象的DLL初始化和销毁:

如果要查看链接.dll时执行的实际代码,请查看
%ProgramFiles%\visualstudio 8\vc\crt\src\dllcrt0.c


从检查中,析构函数将被调用,通过代码> > CXEIT()/CUD>当DLL CRT保持的内部引用计数达到0。

< P>在Windows C++ +DLL中,所有的全局对象(包括类的静态成员)将在DLLIGRADE进程调用DLLYPROPATIONEXPLAN之前构建,它们将在调用DllMain和Dllu进程分离后立即销毁

现在,你必须考虑三个问题:

0-当然,全局非常量对象是邪恶的(但是你已经知道了,所以我将避免提及多线程、锁、上帝对象等等)

1-不保证对象或不同编译单元(即CPP文件)的构造顺序,因此如果两个对象在两个不同的CPP中实例化,则不能希望对象A在B之前构造。如果B依赖于A,这一点很重要。解决方案是在同一CPP文件中移动所有全局对象,因为在同一编译单元中,对象的实例化顺序将是构造顺序(与破坏顺序相反)

2-有些事情是禁止在校园里做的。这些东西可能也被禁止在构造器中使用。所以不要锁东西。请参阅陈雷蒙关于该主题的优秀博客:

在这种情况下,延迟初始化可能很有趣:类保持“未初始化”状态(内部指针为NULL,布尔值为false,等等),直到您调用它们的方法之一,此时它们将自己初始化。如果在main(或main的子函数之一)中使用这些对象,就可以了,因为它们将在执行DllMain之后被调用

3-当然,如果DLL A中的某些全局对象依赖于DLL B中的全局对象,那么您应该非常小心DLL加载顺序,以及依赖关系。在这种情况下,具有直接或间接循环依赖性的DLL将给您带来大量的头痛。最好的解决方案是打破循环依赖关系


S.S:注意,C++中,构造函数可以抛出,并且不希望在DLL加载中间出现异常,因此请确保您的全局对象不会使用异常,而没有非常充分的理由。由于正确写入的析构函数无权抛出,因此在这种情况下DLL卸载应该是正常的。

在扩展名为*.exe的windows二进制图像文件中,*.DLL处于 这样的文件有入口点。您可以使用dumpbin工具查看它,如

dumpbin/headers dllname.dll

如果您使用Microsoft的C运行时,那么您的入口点如下 *CRTStartup或*DllMainCRTStartup

这些函数分别执行C和C++运行时的初始化,并将委托执行分别为(main,Win)或DLLmain。 如果您使用Microsofts VC编译器,则可以在您的VC目录中查看此函数的源代码:

  • crt0.c
  • dllcrt0.c
DllMainCRTStartup process在正常情况下,当它在DLL卸载期间检索通知DLL\u process\u DETACH时,所有东西都需要从.data节初始化/取消初始化全局变量。例如:

  • 程序启动线程的main或WinMain返回控制流
  • 您明确地调用FreeLibrary并使用dll计数器为零

如果一个进程更改了全局值,是否在另一个进程中观察到该更改?@LB--:通常,否:每个进程都有自己的全局变量,除非您碰巧将它们映射到共享内存中,或者使用特定于操作系统的技巧使它们在使用该DLL的所有进程之间共享(我不记得Windows上到底是什么把戏,但它涉及到了#pragma声明,IIRC)