C++ 释放在不同DLL中分配的内存

C++ 释放在不同DLL中分配的内存,c++,debugging,memory-management,dll,assert,C++,Debugging,Memory Management,Dll,Assert,我有一个EXE文件,它使用的是另一个DLL文件。出现了这种情况: 在DLL文件1中: class abc { static bool FindSubFolders(const std::string & sFolderToCheck, std::vector< std::string > & vecSubFoldersFound); } 我假设这是因为内存已在DLL文件1的堆上分配,但正在DLL

我有一个EXE文件,它使用的是另一个DLL文件。出现了这种情况:

在DLL文件1中:

class abc
{
    static bool FindSubFolders(const std::string & sFolderToCheck, 
                               std::vector< std::string > & vecSubFoldersFound);
}
我假设这是因为内存已在DLL文件1的堆上分配,但正在DLL文件2中释放

dbgheap.c
中的注释似乎坚持认为这是一个问题


为什么这是一个这样的问题,当它似乎工作良好,如果我只是忽略它?有没有一种非断言失败的方法可以做到这一点?

最有可能的是,发布版本也有同样的问题,但发布版本不断言。他们只是忽视了这个问题。你可能永远看不到问题。或者您可能会看到数据损坏。或者你可能会看到撞车。也许只有你的用户会遇到你根本无法复制的bug

不要忽略CRT断言

您应该始终使用适当的deallocator(与最初使用的分配器匹配的deallocator)。如果在DLL文件中使用静态CRT库,则DLL文件使用不同的堆。不能跨堆释放内存。使用同一堆分配和取消分配内存块


如果您在DLL文件中使用共享CRT库,那么它们应该使用相同的堆,您可以在一个DLL文件中分配,在另一个DLL文件中取消分配。

正如sean已经说过的,发布版本只会忽略delete语句,因此您最好的希望是内存泄漏

如果您可以控制如何编译这两个DLL文件,请确保对运行库使用多线程调试DLL(/MDd)或多线程DLL(/MD)设置。这样,两个DLL文件将使用相同的运行时系统并共享相同的堆


缺点是您需要将运行时系统与应用程序一起安装(Microsoft为此提供了安装程序)。由于Visual Studio也安装了该运行时系统,因此它在您的开发计算机上可以正常工作,但在新安装的计算机上,它会报告缺少的DLL文件。

只有当应用程序或一个(或多个)DLL文件链接到标准库的静态版本时,这才是一个问题。大约十年前,微软发布了标准库的共享库版本,解决了这个问题。这是因为标准库的每个版本都将构建自己的内部堆,因此对于多个堆,您必须将内存释放到正确的堆中。通过使用标准库的共享版本,它们都使用相同的堆

这是目前应用程序的标准做法,所有DLL文件都应使用标准库的动态版本构建


上面唯一需要注意的是,如果您创建自己的堆并从该堆分配内存。但这是一个非常专门的程序,只在极少数情况下才会执行(如果你足够理解并使用它,那么你就不会提出这个问题)

正如other所说,通过确保两个模块之间共享CRT,可以解决问题。但在一些常见的情况下,该合同很难执行

原因是,如果EXE和DLL没有链接到同一个CRT版本(如6.0、7.0、8.0),那么确保链接到共享CRT将不起作用。例如,如果您使用VC6.0中构建的DLL,并尝试将其与VS2010中的EXE构建一起使用,您将遇到与以前相同的问题。CRT的两个版本将加载到您的进程中,并且每个版本都使用自己的堆进行分配,无论您的EXE和DLL是否使用“共享”CRT,它们都将不相同


对于API来说,更好的做法是确保在一侧分配的对象也在同一侧销毁。我知道这听起来很难听,但这是确保DLL保持二进制兼容的唯一方法。

不是。忽略。信息技术这就是为什么。我问=我只是想知道为什么这是个问题。雷蒙德·陈:我的项目属性是错误的——我没有设置调试DLL(/MDd)——它现在可以正常工作了。谢谢使用多态分配器版本的
vector
string
有效吗?因为他们会调用多态分配函数,哪个函数(可能)会指向DLL中的代码?
void aFunction()
{
    std::vector<std::string> folders;
    std::string sLocation;
    ...
    abc::FindSubFolders(sLocation, folders)
}
/*
 * If this ASSERT fails, a bad pointer has been passed in. It may be
 * totally bogus, or it may have been allocated from another heap.
 * The pointer MUST come from the 'local' heap.
 */
_ASSERTE(_CrtIsValidHeapPointer(pUserData));