Platform::StringReference
的存在使得您可以跨 ABI 边界将 const wchar_t*
传递给接受 String^
的函数,而无需复印。 StringReference
隐式转换为 String^
,其内部指针与原始 const wchar_t*
匹配。这是通过以下代码验证的;如果你单步执行它,你会发现pz == z
:
void param(String^ s)
{
const wchar_t* z = s->Data();
}
App::App()
{
std::wstring p = L"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
const wchar_t* pz = p.c_str();
param(StringReference(pz));
}
但是,尝试返回 StringReference
似乎并没有以同样的方式工作,我很好奇为什么。如果我有一个返回 String^
的函数,并且从中返回一个 StringReference
,则调用相同的隐式转换运算符,但是当调用者获取其 String^ 时
它有一个不同的内部数据指针,其中包含一个副本。下面是一些尝试它的代码:
String^ ret()
{
std::wstring s = L"12345678901234567890123456789012345678901234567890";
const wchar_t* z = s.c_str();
return StringReference(z);
}
App::App()
{
String^ r = ret();
const wchar_t* rz = r->Data();
}
该代码通过两种方式进行验证:首先,如果您单步执行,您会发现 z != rz
,其次,r
最终指向一个有效的字符串而不是垃圾,因此必须创建一个副本,因为原始字符串在 ret
末尾被释放。
我也尝试通过 out 参数返回,但得到与直接返回相同的结果(z != oz
和 o
最终得到一个有效的字符串):
void out(String^* r)
{
std::wstring s = L"12345678901234567890123456789012345678901234567890";
const wchar_t* z = s.c_str();
*r = StringReference(z);
}
App::App()
{
String^ o;
out(&o);
const wchar_t* oz = o->Data();
}
是否有一种方法可以像传递 StringReference 一样跨越 ABI 边界返回 StringReference?我想该行为将取决于调用者的语言以及该语言如何从 WinRT 编码字符串,但看起来至少 C++/CX 调用者应该能够做到这一点。
最佳答案
不,您不能跨 ABI 边界返回 StringReference。跨 ABI 边界返回 StringReference 与返回局部变量的地址类似(但不相同)。这是因为 StringReference 的全部要点是 StringReference 不会分配任何新内存。
考虑一下如果您可以跨 ABI 边界返回 StringReference 会发生什么。如果你有的话会发生什么:
String^ ReturnAString()
{
const wchar_t buffer[500] = "MyString";
return StringReference(buffer);
}
StringReference
只是堆栈分配的缓冲区
的包装。显然,您不能跨 ABI 边界返回该值(一旦例程退出,堆栈存储就会被回收)。
相反,您需要返回一个真正的 Platform::String - Platform::String 包含字符串数据的副本,因此可以安全地将其返回给调用者。
关于string - C++/CX : Why doesn't returning a StringReference work like passing one as an argument?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17727524/