从 DLL 返回 std::wstring 是不是安全?

Posted

技术标签:

【中文标题】从 DLL 返回 std::wstring 是不是安全?【英文标题】:Is it safe to return std::wstring from a DLL?从 DLL 返回 std::wstring 是否安全? 【发布时间】:2014-01-05 23:20:52 【问题描述】:

根据一些较早的 *** 问题(Unable to pass std::wstring across DLL、C++ DLL returning pointer to std::list<std::wstring>),C++ DLL 返回 std::wstring 是不安全的,因为不能保证主程序具有相同的 std::wstring 定义,因此它可能会导致崩溃。

但是,在 http://en.cppreference.com/w/cpp/string/basic_string 中,似乎 std::wstring 现在可以与 WCHAR 数组互换使用:

(C++11 起) basic_string 的元素是连续存储的,即对于 basic_string s,&*(s.begin() + n) == &*s.begin() + n 对于 [0, s.size( )),或者等效地,可以将指向 s[0] 的指针传递给期望指向 CharT[] 数组的第一个元素的指针的函数。

我已经通过将&amp;s[0] 传递给预期WCHAR* 缓冲区的WINAPI 函数对此进行了测试,并且它似乎可以工作(std::wstring 已正确填充了WINAPI 的结果)。因此,既然std::wstring 现在显然可以被视为WCHAR 数组,我决定重新审视这个问题:可以从DLL 安全地返回std::wstring 吗?为什么或为什么不?

【问题讨论】:

【参考方案1】:

在跨 DLL 边界传递 C++ 对象方面没有任何改变。由于与以前相同的原因,这仍然是不允许的。边界另一边的模块可能对类有不同的定义。

&amp;s[0] 是指向字符数组的有效可修改指针这一事实并不真正相关。因为std::basic_string 不仅仅是一个字符数组。

请记住,std::basic_string 的每个实现都可以有不同的内部存储。 operator[] 可以有不同的实现。可以从不同的堆中分配。以此类推。

我认为可以安全地假设跨通用 DLL 边界传递 C++ 对象永远不会有效。仅当您保证边界的两侧都链接到同一个运行时实例时才可行。

【讨论】:

我很困惑为什么 std::wstring 可以安全地传递给 WinAPI 但不能传递给使用不同 C++ 编译器构建的程序。直接修改wstring 的字符数组不会使wstring 实现具有的任何其他信息无效吗?但出于某种原因,它起作用了,所以对我来说,wstring 似乎更容易接受其他形式的修改/分配。 您不会将 std::wstring 传递给 Win32 API 函数。您让std::wstring 为您提供wchar_t*,允许写入。 Win32 API 函数确实在修改内部字符缓冲区。但是std::wstring 不仅仅是一个字符缓冲区。 我知道我将wstring 的字符缓冲区而不是wstring 本身传递给WinAPI。但是当wstring 的字符缓冲区被这样直接修改时,它不会失效吗?因此,我假设该类变得更加健壮和/或与其他类兼容。 @computerfreaker 可以这样想。假设一个运行时将std::basic_string 定义为具有私有成员bufferlength 的类。但是另一个运行时以相反的顺序对成员执行完全相同的操作。两个运行时都无法理解对方的类型。它们只是不同的类型。这就是它归结为的根本原因。还有其他问题。就像调用约定可能不同一样。分配不同的堆。真的,问题的清单是无穷无尽的! 可能值得注意的是,如果它是仅由您的应用程序使用的“内部”dll,并且您使用相同的编译器、编译器设置、库等构建所有内容,那么它实际上可以毫无问题地工作。跨度>

以上是关于从 DLL 返回 std::wstring 是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PInvoke 将 std::wstring 从 C++ 返回到 C# 而无需编写字符串缓冲区转换 [重复]

从 dll 导出 std::vector 时出现链接错误

未解析的外部使用 fmt::format 返回 std::wstring

在 c++ 中为非托管 c# dll 使用 std::string

从 std::string 和 std::wstring 获取 char 整数值

将 std::wstring 从 Visual Studio 移植到 mingw gcc