假设我用C ++编写了一个DLL,并使用一个非平凡的析构函数声明了一个类的全局对象。 卸载DLL时将调用析构函数吗?

===============>>#1 票数:37 已采纳

在Windows C ++ DLL中,所有全局对象(包括类的静态成员)都将在使用DLL_PROCESS_ATTACH调用DllMain之前构造,并且在使用DLL_PROCESS_DETACH调用DllMain之后立即销毁它们。

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

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

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

2-DllMain中禁止执行某些操作。 这些东西也可能在构造函数中被禁止。 因此,避免锁定某些东西。 请参阅Raymond Chen关于该主题的出色博客:

http://blogs.msdn.com/oldnewthing/archive/2004/01/27/63401.aspx

http://blogs.msdn.com/oldnewthing/archive/2004/01/28/63880.aspx

在这种情况下,惰性初始化可能会很有趣:类将保持“未初始化”状态(内部指针为NULL,布尔值为False,无论如何),直到您调用它们的方法之一为止,此时它们将自行初始化。 如果在主体(或主体的后代函数之一)中使用这些对象,您会没事的,因为在执行DllMain之后将调用它们。

3-当然,如果DLL A中的某些全局对象依赖于DLL B中的全局对象,则您应非常小心DLL的加载顺序,并因此确保依赖关系。 在这种情况下,具有直接或间接循环依赖关系的DLL将使您发疯。 最好的解决方案是打破循环依赖。

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

===============>>#2 票数:6

Microsoft的本页详细介绍了DLL初始化和全局变量销毁的细节:
http://msdn.microsoft.com/en-us/library/988ye33t.aspx

===============>>#3 票数:4

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

从检查来看,当由dll CRT维护的内部引用计数达到零时,将通过_cexit()调用析构函数。

===============>>#4 票数:3

在应用程序结束或DLL卸载时(以先到者为准)应调用它。 请注意,这在某种程度上取决于要编译的实际运行时。

另外,请注意非平凡的析构函数,因为同时存在时序和排序问题。 在析构函数所依赖的DLL 之后,您的DLL可能会被卸载,这显然会引起问题。

===============>>#5 票数:1

在Windows扩展名为* .exe的二进制图像文件中,*。dll为PE格式。此类文件具有入口点。 您可以使用dumpbin工具查看它

dumpbin / headers dllname.dll

如果使用Microsoft的C运行时,则入口点将类似于* CRTStartup或* DllMainCRTStartup

这些函数执行c和c ++运行时的初始化,并将执行分别委派给(main,WinMain)或DllMain。

如果使用Microsoft的VC编译器,则可以在VC目录中查看此函数的源代码:

  • crt0.c
  • dllcrt0.c

在正常情况下,DllMainCRTStartup过程处理所有事情都需要从.data节中初始化/取消初始化全局变量,当它在dll卸载期间检索通知DLL_PROCESS_DETACH时。 例如:

  • 程序启动线程的main或WinMain返回控制流
  • 您明确地调用FreeLibrary并且use-dll-counter为零

===============>>#6 票数:1

当调用带有fdwReason = DLL_PROCESS_DETACH参数的DllMain时,这意味着该DLL已由应用程序卸载。 这是调用全局/静态对象的析构函数之前的时间。

  ask by Dima translate from so

未解决问题?本站智能推荐:

4回复

存储在内存中的DLL的全局变量在哪里?

假设您有一个使用C ++ DLL的VB6应用程序。 它们共享相同的内存(您可以使用另一个中的指针)。 使用Public Declare Function ... Lib ...在VB6应用程序中Public Declare Function ... Lib ... DLL Public De
1回复

DLL中全局变量的使用限制(对于Windows)

首先,我知道全局变量是有害的:)但是,在合法情况下,为什么我需要使用一个。 我知道在DllMain中可以执行什么有非常严格的限制(没有LoadLibraries,没有COM初始化等等)。 而且我知道全局变量仅在DllMain DLL_PROCESS_ATTACH之前初始化。 全
2回复

C ++ DLL中的全局变量的范围是什么

假设第三方DLL X具有全局变量G. 我写了两个独立的DLL(作为应用程序的插件) P1和P2 ,它们都动态加载X. 应用程序的进程加载了我的两个插件P1和P2,因此两个插件同时加载。 这是否意味着我有一个G或两个实例? 编辑: 使用场景是X是一个3D渲染引擎,它具
2回复

在C ++ DLL中使用全局变量

我有一个带有3个类的C ++ DLL。 我在我的“ stdafx”头文件中添加了一个静态布尔变量(因为我所有的类都包含了它),并且正在尝试使用它。 当我所有的类都看到我的变量时,它们似乎都具有不同的实例。 如果在一次类中将变量设置为true,那么我会注意到在另一个类中该变量为false。
2回复

如何模仿静态库但使用DLL的“应用程序中的全局变量的多个实例”行为?

我们有一个用C / C ++编写的应用程序,它分为单个EXE和多个DLL。 这些DLL中的每一个都使用相同的静态库( utilities.lib )。 实用程序静态库中的任何全局变量实际上都会在应用程序中的运行时具有多个实例。 每个模块(即DLL或EXE)的一个全局变量副本将与util
1回复

DLL多次链接时导出的全局变量会发生什么变化?

假设我在头文件中有一个带有以下内容的X.DLL : 然后在实现文件中的X.DLL中定义此foobar全局变量: 现在假设我有两个DLL, A.DLL和B.DLL ,它们链接到X.DLL ,以及一个使用A.DLL和B.DLL的应用程序E.EXE : 在这种情况下,是表达式&
3回复

具有来自同一DLL的全局变量的多个实例

目前,我的系统具有以下简化视图。 COMMON.DLL的源代码如下。 DLL0.DLL的源代码如下。 DLL1.DLL的源如下。 EXE的源代码如下。 输出如下。 整个系统在单个过程中执行。 尽管DLL0.DLL和DLL1.DLL分别被显式
2回复

在同一DLL的实例之间共享静态和全局变量

首先,有一些类似的问题,但没有一个真正解决确切的问题: https://social.msdn.microsoft.com/forums/vstudio/en-US/b7701ee5-c9fa-4693-8ae1-d59736360514/question-about-static-var
2回复

DLL中的全局指针

我有一个C ++ DLL项目,它包含一个dllmain源文件,一个只包含DLL函数声明的头文件,一个包含完整函数定义的cpp文件,以及一个指向不同类实例的全局指针。 通过调用Init函数初始化此指针,并且所有其余DLL函数都使用指针并返回错误(如果尚未分配)。 除了依赖用户在完成DLL时
1回复

如何使用公开导出的全局DLL变量?

说我有2个简单的类A和C ,也有以A和C指针形式的全局外部变量。 码: 我只列出了DLL代码。 关键是让DLL用户从他的EXE代码中声明(声明)说main.cpp全局变量供我的DLL代码使用。 因此,当我想在DLL项目中的多个文件中使用该外部变量时,用户不在同一项目中。 我从