DLL中的C ++静态对象没有调用析构函数

时间:2014-03-19 08:35:52

标签: c++ dll destructor

我遇到的问题是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中描述的一样。此页面详细说明了如何调用构造函数,但没有详细说明如何调用析构函数。在下面的段落中,它提到了调用哪些函数来调用构造函数的细节,我可以在callstack中看到它。

“C / C ++运行时库代码执行DLL启动顺序,无需在Windows 3.x中根据需要链接单独的模块.C / C ++运行时库代码中包含的是名为_DllMainCRTStartup的DLL入口点函数._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

由于

2 个答案:

答案 0 :(得分:0)

这是我的经历。

我使用LoadLibrary明确地绑定了我的DLL。 调用FreeLibrary时,析构函数内部发生了一些访问冲突。 在从(* function_to_call)()调用的析构函数之后立即卸载DLL;在DLL中已被取消。

奇怪的是Visual Studio在发生访问冲突时不会中断。 然后从FreeLibrary继续执行,好像程序完成没有错误。 它看起来一切正常,除了一些没有析构函数的静态对象。

我发现了以下设置的错误。当我的DLL中的析构函数内发生访问冲突时,这改变了Visual Studio的行为。

enter image description here

Ctrl + Alt + E显示此对话框。 那时我使用的是Visual Studio 2010。

答案 1 :(得分:0)

静态析构函数通常由C ++运行时注册,以通过dict_maker函数运行。但它们仅针对应用程序注册,而不是DLL。原因是DLL可以即时加载和卸载。如果DLL注册了atexit函数,那么当卸载DLL时这些函数指针会悬空,并且当程序实际退出时会导致崩溃。

尽量避免DLL中的静态对象。如果你绝对需要它们,那么在库中公开初始化和清理函数,以便用户可以处理它。然后将这些变量转换为指针,将atexit()转换为init,new将它们转换为deinit。