我无法弄清楚以下崩溃的原因 (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 之类的包装器。
最佳答案
这实际上并不是由不同的堆实现引起的——MSVC std::string 实现不为那么小的字符串使用动态分配的内存(它使用小字符串优化)。 CRT 确实需要匹配,但这次不是你的问题。
发生的情况是您通过违反一个定义规则来调用未定义的行为。
发布和调试版本将设置不同的预处理器标志,您会发现 std::string
在每种情况下都有不同的定义。询问您的编译器 sizeof(std::string)
是什么 - MSVC10 告诉我它在调试版本中为 32,在发布版本中为 28(这不是填充 - 28 和 32 都是 4 个字节` 边界)。
那么发生了什么?变量 s
使用复制构造函数的调试版本来初始化,以复制 std::string
的发布版本。成员变量的偏移量在版本之间是不同的,所以你复制垃圾。 MSVC 实现有效地存储了开始和结束指针——您已将垃圾复制到其中;因为它们不再为 null,所以析构函数会尝试释放它们,但您会遇到访问冲突。
即使堆实现相同,它也会崩溃,因为您正在释放指向从未分配过的内存的垃圾指针。
总而言之:CRT 版本需要匹配,但定义也是如此 - 包括标准库中的定义。
关于c++ - 为什么这个程序会崩溃:在 DLL 之间传递 std::string,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2322095/