【发布时间】:2014-03-19 08:35:51
【问题描述】:
我遇到了一个问题,即 DLL 中的静态析构函数没有被调用。正在调用构造函数,但没有调用析构函数。我的 DLL 中有一个这样的类
struct DLLDestructorTest
{
int blah;
DLLDestructorTest()
{
blah = 2;
}
~DLLDestructorTest()
{
blah = 0;
}
};
DLLDestructorTest DLLDestructorTestObj;
我可以在构造函数和析构函数中放置断点,并且可以验证构造函数断点是否命中而析构函数断点未命中。如果我在 main.cpp 文件中放入类似的代码块,我可以验证构造函数和析构函数都会被调用。
构造函数调用时的调用栈如下。
mydll.dll!mydll::DLLDestructorTest::DLLDestructorTest() Line 1093 C++
mydll.dll!mydll::`dynamic initializer for 'DLLDestructorTestObj''() Line 1100 + 0x26 bytes C++
msvcr90d.dll!_initterm(void (void)* * pfbegin=0x000007fee7f521a8, void (void)* * pfend=0x000007fee7f52bf8) Line 903 C
mydll.dll!_CRT_INIT(void * hDllHandle=0x000007fee7920000, unsigned long dwReason=1, void * lpreserved=0x00000000002cf580) Line 323 C
mydll.dll!__DllMainCRTStartup(void * hDllHandle=0x000007fee7920000, unsigned long dwReason=1, void * lpreserved=0x00000000002cf580) Line 540 + 0x13 bytes C
mydll.dll!_DllMainCRTStartup(void * hDllHandle=0x000007fee7920000, unsigned long dwReason=1, void * lpreserved=0x00000000002cf580) Line 511 C
这基本上与此网页http://msdn.microsoft.com/en-us/library/988ye33t.aspx 上的描述相同,此页面提供了有关如何调用构造函数的详细信息,但没有关于如何调用析构函数的详细信息。在下面的段落中,它提到了有关调用哪些函数来调用构造函数的详细信息,我可以在我的调用堆栈中看到。
“C/C++ 运行时库代码执行 DLL 启动序列,无需像在 Windows 3.x 中那样与单独的模块链接。C/C++ 运行时库代码中包括DLL 入口点函数称为 _DllMainCRTStartup。_DllMainCRTStartup 函数做了几件事,包括调用 _CRT_INIT,它初始化 C/C++ 运行时库并在静态、非局部变量上调用 C++ 构造函数。没有这个函数,运行时库将处于未初始化状态。_CRT_INIT 可用于静态链接的 CRT 或从用户 DLL 链接到 CRT DLL Msvcr90.dll。"
我在这里找到了一篇帖子What happens to global variables declared in a DLL?,但这似乎只是说明将调用析构函数。
任何关于为什么不调用析构函数的想法将不胜感激。
谢谢, 约翰·劳里
更新
我已经看过这个并阅读了有关 DLL 的信息,但仍然没有解决方案。 DLL 与 __declspec(dllexport) 隐式链接。据我了解,卸载 DLL 不需要做任何特别的事情。它应该在进程终止时自动卸载。
我按照本页http://msdn.microsoft.com/en-us/library/ms235636(v=vs.90).aspx 上的说明制作了一个非常简单的DLL。我对从此项目调用析构函数没有任何问题。
我尝试比较这个简单项目和我当前的项目之间发生的情况。如果我将断点放在简单的测试项目DLL析构函数中,我可以查看调用堆栈并看到析构函数是从
crtdll.c line 447
crtdll.c line 560
crtdll.c line 510
在我当前的项目中,我可以看到它正在进入一个不同的 __DllMainCRTStartup 函数并在第 521 行开始执行。它最终到达了第 447 行的同一行,即 (*function_to_call)();但我的析构函数没有被调用。
如果有用的话,我调用的 DLL 是来自 juce.com 的 JUCE
谢谢
【问题讨论】:
-
对不起,如果这是一个非常幼稚的评论,但是......你如何卸载你的图书馆?你的程序是如何终止的?如果进程退出,那么肯定会调用析构函数,如果终止则不会。
-
尝试使用
cout等代替blah = 0打印内容,看看是否打印/记录了任何内容。 -
使用调试器和设置断点会掩盖正在发生的事情。除了使用调试器之外,您应该做的是调用诸如
OutputDebugString("Destructor is called")之类的函数。然后您检查该字符串是否显示在您的调试监视器/输出窗口(如果您正在使用 Visual Studio,或者如果没有,则类似于 www.sysinternals.com 中的 DebugView)。 -
我已经使用 OutputDebugString 验证了析构函数不是为 DLL 中的析构函数调用的,而是为我的 main.cpp 文件中的析构函数调用的。我现在要研究这个 DLL 是如何被卸载的。据我所知,程序正常退出,但我将对此进行调查。
-
所以我检查了我的程序流程,这就是我发现的。该程序似乎正常退出,没有异常或中止调用。它从 crtexe.c 中的 WinMain 返回,状态为 0。然后 WinMainCRTStartup 调用 exit(0)。它在我的 main.cpp 中的静态类的析构函数被调用。
标签: c++ dll destructor