且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-10-19 09:24:15

静态析构函数通常由C ++运行时注册,以通过 atexit()函数。但是它们仅针对应用程序注册,而不针对DLL注册。原因是DLL可以即时加载和卸载。如果DLL注册了atexit函数,则这些函数指针将在DLL卸载时挂起,并在程序实际退出时导致崩溃。



尝试避免DLL中的静态对象。如果您绝对需要它们,则可以在库中公开初始化和清除函数,以便用户进行处理。然后将这些变量转换为指针,并在初始化时 new 进行初始化,在初始化时删除进行修改。


I am having an issue where static destructors in a DLL are not getting called. The constructor is being called, but the destructor is not. I have a class like this in my DLL

struct DLLDestructorTest
{
    int blah;
    DLLDestructorTest()
    {
        blah = 2;
    }
    ~DLLDestructorTest()
    {
        blah = 0;
    }
};
DLLDestructorTest DLLDestructorTestObj;

I can put breakpoints in the constructor and the destructor and I can verify that the constructor breakpoint is hit and the destructor breakpoint is not. If I put an analogous chunk of code in my main.cpp file, I can verify that both the constructor and destructor will be called.

The call stack when the constructor is called is as follows.

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

Which is basically as described on this webpage http://msdn.microsoft.com/en-us/library/988ye33t.aspx This page give details on how you the constructor is called, but no details as to how the destructor is called. In the following paragraph, it mentions details about which functions are called to invoke the constructor, which I can see in my callstack.

"The C/C++ run-time library code performs the DLL startup sequence, eliminating the need to link with a separate module as was necessary in Windows 3.x. Included in the C/C++ run-time library code is the DLL entry-point function called _DllMainCRTStartup. The _DllMainCRTStartup function does several things, including calling _CRT_INIT, which initializes the C/C++ run-time library and invokes C++ constructors on static, non-local variables. Without this function, the run-time library would be left in an uninitialized state. _CRT_INIT is available for both a statically linked CRT or linking to the CRT DLL Msvcr90.dll, from a user DLL."

I found one post here What happens to global variables declared in a DLL?, but this just seems to state that destructors will be called.

Any ideas as to why the destructors are not called would be appreciated.

Thanks, John Lawrie

Update

I have looked at this and have read up about DLLs but still don't have the solution. The DLL is linked implicitly with __declspec(dllexport). As far as I understand, there is nothing special that I should need to do to unload the DLL. It should unload automatically when the process terminates.

I made an very simple DLL by following the instructions on this page http://msdn.microsoft.com/en-us/library/ms235636(v=vs.90).aspx. I have no problems with the destructors getting called from this project.

I tried comparing what happens between this simple project and my current one. If I put the breakpoint in the simple test project DLL destructor, I can check out the call stack and see that the destructor is called from

crtdll.c line 447
crtdll.c line 560
crtdll.c line 510

In my current project, I can see that it is going into a different __DllMainCRTStartup function and begins executing at line 521. It does eventually get to the same line of line 447 which is just (*function_to_call)(); but my destructor does not get called.

In case it is useful, the DLL I'm calling is JUCE from juce.com

Thanks

Static destructors are typically registered by the C++ runtime to run via the atexit() function. But they are registered only for applications, not DLLs. And the reason is that DLLs can be loaded and unloaded on the fly. If DLLs registered atexit functions, those function pointers would dangle when the DLL is unloaded and would cause a crash when the program actually exits.

Try to avoid static objects in DLLs. If you absolutely need to have them, then expose initialization and cleanup functions in the library so the user can deal with this. Then convert those variables to pointers and new them on init, delete them on deinit.