C++ 卸载DLL后,是否可以存储在DLL中创建的对象?

C++ 卸载DLL后,是否可以存储在DLL中创建的对象?,c++,winapi,memory-management,dll,C++,Winapi,Memory Management,Dll,我需要一些关于以下代码的澄清 在下面的代码中,我从DLL检索接口的私有实现 卸载DLL后(案例#2),从接口检索到的字符串和接口本身都将无效,访问时会发生(预期)访问冲突 但让我困惑的是,当我重新加载DLL时,我可以再次使用接口和字符串,而无需从DLL中重新检索它们 这样行吗 内存怎么会变得无效,一旦DLL再次加载,它们又会突然变为有效 这仅仅是运气吗?由于我的测试程序相对简单,DLL第二次很方便地加载到内存中完全相同的位置 int main(int argc, int *argv[]) {

我需要一些关于以下代码的澄清

在下面的代码中,我从DLL检索接口的私有实现

卸载DLL后(案例#2),从接口检索到的字符串和接口本身都将无效,访问时会发生(预期)访问冲突

但让我困惑的是,当我重新加载DLL时,我可以再次使用接口和字符串,而无需从DLL中重新检索它们

这样行吗

内存怎么会变得无效,一旦DLL再次加载,它们又会突然变为有效

这仅仅是运气吗?由于我的测试程序相对简单,DLL第二次很方便地加载到内存中完全相同的位置

int main(int argc, int *argv[])
{
    Interface *itf;
    const char *name;

    {
        // loads the dll and gets functions
        PersistenInterface pi("PersistentInterface.dll");

        // returns a private implementation of the interface
        itf = pi.CreateInterface();
        name = itf->GetName();

        // CASE #1
        cout << name << endl; // suceeds

    } // dll is unloaded in ~PersistenInterface()

    // CASE #2
    //cout << name << endl; // crashes
    //cout << itf->GetName() << endl; // crashes

    {
        PersistenInterface pi("PersistentInterface.dll");

        // CASE #3
        cout << name << endl; // suceeds !?
        cout << itf->GetName() << endl; // suceeds !?
    }

    return 0;
}
int main(int argc,int*argv[])
{
接口*itf;
常量字符*名称;
{
//加载dll并获取函数
persistenterface pi(“persistenterface.dll”);
//返回接口的私有实现
itf=pi.CreateInterface();
name=itf->GetName();
//案例1

cout我希望您没有从DLL返回堆栈上的本地对象。这肯定会使您的系统崩溃,因为从DLL返回函数后,本地对象将被销毁。这与DLL的概念无关。如果您尝试在包含函数返回后引用本地对象,您将看到相同的问题

如果在DLL内部的堆上动态分配内存,则在DLL未初始化后仍然有效。您仍然可以在主应用程序中使用内存,因为DLL本身不拥有任何内容。请记住,堆属于进程,而不是DLL


但是,一般规则是该内存的所有者(创建该内存的人,例如,在您的案例中的DLL)负责释放相同的内存。在DLL中分配内存并在另一端取消分配内存可能会给您带来不必要的麻烦,如果双方使用不同的CRT实例,例如,

答案有点复杂。实际上,如果加载DLL,它并不是真的加载到堆内存中。它加载到全局内存中,而这个emory被映射到您的地址空间。使用此机制,操作系统可以节省内存,因为它可以将相同的代码映射到不同的进程。因此,如果您访问DLL空间中的地址,访问将重定向到DLL真正存在的全局内存中。卸载后,此地址上不再有内存。您的访问将不再存在如果不再重定向,将引发异常。这与malloc和free(或new和delete)不同,在malloc和free(或new和delete)中,只有内存被标记为未使用,但其所有数据仍然存在(除非激活了零出内存)。静态DLL数据(如常量字符串)DLL的代码与上面描述的一样。再次加载DLL后,您拥有的地址(显然指向静态数据或代码)再次生效。至少Windows XP总是在相同的地址空间加载DLL。但不要依赖于此!出于安全原因,现代操作系统可以决定将进程的DLL映射到不同的地址每次使用loadLibrary或每次启动进程时。在调试器或Windows XP中,DLL总是映射到同一个地址,据我所知,这就是代码行为的原因。这不是错误或功能,而是由DLL概念决定的。

我想知道如何分配
itf
name
n
pi
?“name”已在堆栈上分配。我切换到返回strdup(name),字符串的case#2不再崩溃。接口仍然崩溃,但这是有意义的,因为代码不再加载(pvt imp在dll中)。重新加载dll后,接口将再次工作也是有意义的。我仍然不喜欢的是,我以前有一个.lib,其中包含一个单例,我将它链接到dll和主程序,然后得到了单例的两个唯一副本(一个在应用程序中,一个在dll中。知道为什么吗?“.lib”您提到的是DLL的导入库还是另一个静态链接的DLL库?不,只是一个静态实用程序库,其中包含我在主程序和DLL中需要的东西。正在使用lazy init方法Sinleton&GetSingleton(){static singleton s;return s;}分配单例指针.我可以理解当dll按照之前的情况卸载时会发生这种崩溃,但是为什么会有两个副本?