从 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[] 数组的第一个元素的指针的函数。
我已经通过将&s[0]
传递给预期WCHAR*
缓冲区的WINAPI 函数对此进行了测试,并且它似乎可以工作(std::wstring
已正确填充了WINAPI 的结果)。因此,既然std::wstring
现在显然可以被视为WCHAR
数组,我决定重新审视这个问题:可以从DLL 安全地返回std::wstring
吗?为什么或为什么不?
【问题讨论】:
【参考方案1】:在跨 DLL 边界传递 C++ 对象方面没有任何改变。由于与以前相同的原因,这仍然是不允许的。边界另一边的模块可能对类有不同的定义。
&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
定义为具有私有成员buffer
和length
的类。但是另一个运行时以相反的顺序对成员执行完全相同的操作。两个运行时都无法理解对方的类型。它们只是不同的类型。这就是它归结为的根本原因。还有其他问题。就像调用约定可能不同一样。分配不同的堆。真的,问题的清单是无穷无尽的!
可能值得注意的是,如果它是仅由您的应用程序使用的“内部”dll,并且您使用相同的编译器、编译器设置、库等构建所有内容,那么它实际上可以毫无问题地工作。跨度>
以上是关于从 DLL 返回 std::wstring 是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 PInvoke 将 std::wstring 从 C++ 返回到 C# 而无需编写字符串缓冲区转换 [重复]
未解析的外部使用 fmt::format 返回 std::wstring
在 c++ 中为非托管 c# dll 使用 std::string