我正在调用一个静态链接的.dll,我看到了这个错误:
我写了.dll和调用代码。不应该发生此错误。我想知道是否有其他人以前遇到过它? .dll只包含大约10行代码,它只是一个测试.dll来查看dll如何工作。当我将std :: string传回.dll时,它会爆炸。
我正在使用Visual Studio 2012和C ++。
接下来我会尝试
来自Debug assertion... _pFirstBlock == pHead:
如果在a中使用单线程库,则可能会发生此问题 多线程模块。
明天,我将尝试在多线程模式下重新编译Boost静态库(我的.dll设置为多线程静态模式)。
接下来我会尝试
请参阅Using strings in an object exported from a DLL causes runtime error:
你需要做两件事之一
- 使DLL和使用它的客户端都链接到CRT的 DLL 版本(例如,不是静态的)。
- OR您需要确保不跨DLL边界传递动态分配的内存(例如字符串对象中包含的内存)。 换句话说,没有返回字符串的DLL导出函数 对象。
醇>乔
这似乎与最新情况相符,它在我将字符串传回.dll边界的精确点上爆炸。只有在静态模式下链接所有内容时才会出现此问题。现在这是可以修复的。
请参阅Passing reference to STL vector over dll boundary。
接下来我会尝试
请参阅Unable to pass std::wstring across DLL。
解决方案
我有一个很好的解决方案,请参阅下面的答案。
答案 0 :(得分:36)
在这种情况下,问题是我将std::string
传递回.dll边界。
如果MSVC Runtime library
设置为Multi-threaded Debug DLL (/MDd)
,那么这没问题(工作正常)。
如果MSVC Runtime library
设置为Multi-threaded Debug (/MTd)
,则会抛出此错误,可以使用以下说明修复此错误。
问题是内存是在.dll端分配的,然后在应用程序端释放相同的内存。这意味着内存管理器A正在分配内存,而内存管理器B正在释放相同的内存,这会产生错误。
解决方案是确保传回的所有内存都在DLL中分配 。换句话说,内存总是在应用程序端分配,并在应用程序端释放。
当然,DLL可以在内部分配/释放内存 - 但它无法分配稍后由应用程序释放的内存。
这将不工作:
// Memory is allocated on the .dll side, and freed on the app side, which throws error.
DLL std::string GetString();
这将有效:
// Memory is allocated/freed on the application side, and never allocated in the .dll.
DLL int GetString(std::string& text);
然而,这还不够。
在应用程序端,必须预先分配字符串:
std::string text("");
text.reserve(1024); // Reserves 1024 bytes in the string "text".
在.dll端,必须将文本复制到原始缓冲区中(而不是用.dll端分配的内存覆盖):
text.assign("hello");
有时候,C ++会坚持分配内存。仔细检查预分配是否仍然是:
if (text.capacity < 1024)
{
cout << "Memory was allocated on the .dll side. This will eventually throw an error.";
}
另一种方法是使用std::shared_ptr<std::string>
,所以即使在.dll中分配了内存,它也会被.dll(而不是应用程序端)释放。
另一种方法是接受char *
和长度,表示预先分配的内存量。如果我们想要传回的文本长于预分配内存的长度,则返回错误。
答案 1 :(得分:3)
当{em>表达式参数的计算结果为false时,这就是assert()的样子。此断言存在于C运行时库的Debug构建中,旨在检查分配问题。你的案例中的free()函数。 Debug构建添加额外的检查以确保您正确编写代码。并在发现问题时告诉您。就像在已经释放的分配上调用free()一样,这是一个简单的例子。或者调用free()传递错误的指针值,这是一个棘手的案例。或者当堆被早期代码破坏时调用free(),更难的情况。
这只是他们可以接受的,他们实际上并不知道为什么你的代码弄错了。例如,没有任何方法可以将大红色箭头放在破坏堆的代码上。 Debug + Windows + Call Stack调试器窗口涵盖了简单的案例,它将您带到程序中名为free()的代码。或std::operator delete
用于C ++程序。更难的案例非常非常困难,堆腐败通常是Heisenbug。使断言可重复,以便您可以在报告的地址上设置数据断点是核心策略。为了这个简单的案例交叉手指,祝你好运!
编辑之后:是的,像std :: string这样的C ++类存在跨模块问题肯定是它可以捕获的问题之一。不是Heisenbug,有一个很好的问题。两个基本问题:
解决该问题的唯一方法是确保使用完全相同的构建设置,使用完全相同的编译器版本在程序中构建所有模块。使用/ MD是强制性的,它确保共享CRT,因此程序中只有一个。
答案 2 :(得分:2)
可能的原因:绑定到错误版本的Qt DLL,特别是在将项目从VS2010移动到VS2012时。
这是由于标准库的不同版本和相关的动态分配问题。
答案 3 :(得分:1)
重新安装Windows后我遇到了同样的问题。我的运行时库构建是多线程调试DLL(/MDd
)。
我的解决方案是删除visual studio项目的*.user
文件,删除调试文件夹并重建项目。