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

查看:143
本文介绍了为什么这个程序崩溃:在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.dll中分配字符串 A :: getString()返回,并在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(或可执行文件)之间传递字符串的安全方法是什么?不使用带有自定义删除器的shared_ptr等包装器。

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实现不使用动态分配的内存,用于小的字符串(它使用小字符串优化)。 CRT的确需要匹配,但这不是你这次的一点。

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

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 bytes` boundaries).

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

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 implementations 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天全站免登陆