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

标签 c++ dll memory-management visual-c++

我无法弄清楚以下崩溃的原因 (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/

相关文章:

c# - ReleaseComObject 不适用于静态方法

c++ - 如何与命名构造函数一起处理不可复制成员?

c++ - C++ 中的类型映射

c++ - .net 中的静态链接是不可能的吗?你能用 C++/CLI 写一个包装器吗?

windows - PATH 环境如何影响我正在运行的可执行文件,从使用 msvcr90 到 msvcr80?

c++ - dwPageSize 和 dwAllocationGranularity 之间的关系

C++:如何将字符串拆分为大小均匀的较小字符串?

C++ - 根据上下文实例化派生类

c# - Resourcemanager 返回相同的资源,尽管指定了 CultureInfo

c - C 中缺少数组数据