为什么这个程序崩溃:在DLL之间传递std :: string [英] Why does this program crash: passing of std::string between DLLs

查看:381
本文介绍了为什么这个程序崩溃:在DLL之间传递std :: string的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些麻烦找出为什么下列崩溃(MSVC9):

I have some trouble figuring out why the following crashes (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中释放?

Obviously (?) this is due to the different memory models for the executable and DLL. Could it be that the string A::getString() returns is being allocated in A.dll and freed in main.exe?

如果是这样,为什么 - 和什么将是一个安全的方式在DLL(或可执行文件,为此之间)之间传递字符串?

If so, why - and what would be a safe way to pass strings between DLLs (or executables, for that matter)? Without using wrappers like shared_ptr with a custom deleter.

推荐答案

这实际上不是由不同的堆实现引起的 - MSVC std :: string实现不使用动态分配的内存用于小的字符串(它使用小字符串优化)。

发生的情况是,你是调用未定义的行为,违反了一个定义规则。

What's happening is that you're invoking undefined behaviour by violating the One Definition Rule.

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

The release and debug builds will have different preprocessor flags set, and you'll find that std::string has a different definition in each case. Ask your compiler what sizeof(std::string) is - MSVC10 tells me that it's 32 in a debug build and 28 in a release build (this isn't padding - 28 and 32 are both 4 byte boundaries).

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

So what's happening? Variable s is initialized using the debug version of the copy constructor to copy a release version of std::string. The offsets of the member variables are different between the versions, so you copy garbage. The MSVC implementation effectively stores begin and end pointers - you've copied garbage into them; because they're no longer null, the destructor tries to free them and you get an access violation.

即使堆注入是相同的,它会崩溃,因为你

Even if the heap implentations were the same it would crash, as you're freeing garbage pointers to memory that was never allocated in the first place.

总而言之:CRT版本需要匹配,但,因此定义 - 包括标准库中的定义

In summary: the CRT versions need to match but so do the definitions - including the definitions in the standard library.

这篇关于为什么这个程序崩溃:在DLL之间传递std :: string的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆