c++ - 为什么这个程序崩溃:在DLL之间传递std:: string




memory-management visual-c++ (4)

我无法弄清楚为什么以下崩溃(MSVC9):

//// the following compiles to A.dll with release runtime linked dynamically
//A.h
class A {
  __declspec(dllexport) std::string getString();
};
//A.cpp
#include "A.h"
std::string A::getString() {
   return "I am a string.";
}

//// the following compiles to main.exe with debug runtime linked dynamically
#include "A.h"
int main() {
   A a;
   std::string s = a.getString();
   return 0;
} // crash on exit

显然(?)这是由于可执行文件和DLL的不同内存模型。 可能是字符串A::getString()返回是在A.dll中分配并在main.exe中释放?

如果是这样,为什么 - 以及在DLL(或可执行文件)之间传递字符串的安全方法是什么? 不使用像shared_ptr这样的包装器和自定义删除器。


可能是字符串A :: getString()返回是在A.dll中分配并在main.exe中释放?

是。

如果是这样,为什么 - 以及在DLL(或可执行文件)之间传递字符串的安全方法是什么? 不使用像shared_ptr这样的包装器和自定义删除器。

使用shared_ptr听起来对我来说是个明智之举。 请记住,根据经验,分配和解除分配应该由同一个模块完成,以避免这些故障。

在dll中导出STL对象充其量只是一个棘手的小马。 我建议你先看看this MSDN知识库文章和this文章。


这实际上并不是由不同的堆实现引起的 - MSVC std :: string实现不为小的字符串使用动态分配的内存(它使用小字符串优化)。 CRT确实需要匹配,但这次不是你的意思。

发生的事情是你通过违反一个定义规则来调用未定义的行为。

发布和调试版本将设置不同的预处理程序标志,您会发现std::string在每种情况下都有不同的定义。 询问你的编译器sizeof(std::string)是什么 - MSVC10告诉我它在调试版本中是32,在发布版本中是28(这不是填充 - 28和32都是4字节`边界)。

那么发生了什么? 使用复制构造函数的调试版本初始化变量s以复制std::string的发行版本。 成员变量的偏移量在版本之间是不同的,因此您可以复制垃圾。 MSVC实现有效地存储了开始和结束指针 - 你已经将垃圾复制到它们中; 因为它们不再为null,析构函数会尝试释放它们,并且您会获得访问冲突。

即使堆实现是相同的,它也会崩溃,因为你将垃圾指针释放到从未首先分配的内存中。

总结:CRT版本需要匹配,但定义也是如此 - 包括标准库中的定义


这可能是因为DLL和EXE使用不同的CRT设置进行编译。 因此,当您传递字符串时,会发生一些资源冲突。 检查DLL和可执行文件的项目设置。


除了上面所说的,还要确保平台工具集 (在Properties-> General下)在两个项目中都是相同的。 否则,到达方的字符串内容可能是虚假的。

当使用v100工具集版本的控制台应用程序项目使用设置为v90的库时,发生这种情况。





visual-c++