10

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

在 DLL 文件 1 中:

class abc
{
    static bool FindSubFolders(const std::string & sFolderToCheck, 
                               std::vector< std::string > & vecSubFoldersFound);
}

在 DLL 文件 2 中:

void aFunction()
{
    std::vector<std::string> folders;
    std::string sLocation;
    ...
    abc::FindSubFolders(sLocation, folders)
}

在发布模式下,一切正常。但是在调试模式下,我在文件夹向量之一的析构函数中遇到断言失败std::strings(当文件夹在 aFunction 结束时超出范围时):

dbgheap.c : line 1274

/*
 * 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));

我认为这是因为内存已在 DLL 文件 1 的堆上分配,但在 DLL 文件 2 中被释放。

中的评论dbgheap.c似乎非常坚持认为这是一个问题。

如果我只是忽略它似乎可以正常工作,为什么会出现这样的问题?有没有一种非断言失败的方式来做到这一点?

4

4 回答 4

14

正如肖恩已经说过的,发布版本只是忽略了删除语句,所以你能希望的最好的就是内存泄漏。

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

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

于 2009-10-28T02:20:47.683 回答
8

最有可能的是,发布版本有同样的问题,但发布版本没有断言。他们只是忽略了这个问题。你可能永远看不到问题。或者您可能会看到数据损坏。或者您可能会看到崩溃。也许只有您的用户会遇到您根本无法重现的错误。

不要忽略 CRT 断言。

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

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

于 2009-10-28T02:08:07.387 回答
7

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

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

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

于 2012-11-27T15:22:47.460 回答
5

This is only a problem if the application or one (or more) of the DLL files is linked against the static version of the standard library. This was solved about a decade ago by MS releasing the shared library version of the standard library. This is because each version of the standard library will build it own internal heap and thus with multiple heaps you must release the memory to the correct heap. By using the shared version of the standard library they all use the same heap.

It is standard practice nowadays for the application and all DLL files should be built to use the dynamic version of the standard library.

The only caveat to the above is if you create your own heap and allocate memory from this heap. But this is a very specialized procedure only done in rare situations (and if you understand enough to use it then you will not be in the situation of asking this question).

于 2009-10-28T04:45:29.123 回答