假设我用C++编写一个DLL,并使用一个非平凡的析构函数声明一个类的全局对象.卸载DLL时是否会调用析构函数?
在Windows C++ DLL中,所有全局对象(包括类的静态成员)将在使用DLL_PROCESS_ATTACH调用DllMain之前构造,并且在使用DLL_PROCESS_DETACH调用DllMain之后它们将被销毁.
现在,您必须考虑三个问题:
0 - 当然,全局非const对象是邪恶的(但你已经知道了,所以我将避免提到多线程,锁,神对象等)
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,布尔值为假,无论如何),直到您调用其中一个方法,此时它们将自己初始化.如果你在main(或者一个main的后代函数)中使用那些对象,你就可以了,因为它们将在执行DllMain后被调用.
3 - 当然,如果DLL A中的某些全局对象依赖于DLL B中的全局对象,则应该非常小心DLL加载顺序,从而确保依赖性.在这种情况下,具有直接或间接循环依赖性的DLL将导致您疯狂的头痛.最好的解决方案是打破循环依赖.
PS:请注意,在C++中,构造函数可以抛出,并且您不希望在DLL加载过程中出现异常,因此请确保您的全局对象在没有非常好的理由的情况下不会使用异常.由于正确编写的析构函数无权抛出,因此在这种情况下DLL卸载应该没问题.
Microsoft的这个页面详细介绍了DLL初始化和全局变形的破坏:http:
//msdn.microsoft.com/en-us/library/988ye33t.aspx