C++/CX:为什么';返回一个StringReference工作是否像传递一个参数一样?
C++/CX:为什么';返回一个StringReference工作是否像传递一个参数一样?,string,windows-runtime,c++-cx,String,Windows Runtime,C++ Cx,Platform::StringReference的存在使得您可以将const wchar\u t*通过ABI边界传递给接受String^的函数,而无需复制。StringReference隐式转换为String^,其内部指针与原始const wchar\u t*匹配。这通过以下代码进行验证;如果您仔细查看它,您会发现pz==z: void param(String^ s) { const wchar_t* z = s->Data(); } App::App() { std
Platform::StringReference
的存在使得您可以将const wchar\u t*
通过ABI边界传递给接受String^
的函数,而无需复制。StringReference
隐式转换为String^
,其内部指针与原始const wchar\u 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
以有效字符串结尾):
有没有一种方法可以像传递一个字符串引用一样,跨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包含字符串数据的副本,因此可以安全地返回给调用方。否您不能跨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包含字符串数据的副本,因此可以安全地将其返回给调用方。是的,我知道我的示例通过返回释放的内存做了坏事,但这是我可以确认发生了副本的一种方法。我确实有一个实际的用例,它将返回一个对内存的引用,该内存的生命周期可由调用方控制。用一个特征来拍摄自己的脚并不是一个令人信服的理由,尤其是在C++中。我可以理解高级语言不想暴露这种复杂程度,但这难道不是他们WinRT投影的实现细节吗?这里的问题是Platform::String需要分配。但是,如果您只是向一个方法提供一个字符串,那么就不需要额外的内存分配/释放/复制开销。这就是StringReference的用武之地。C++/CX是为那些希望在更接近金属的环境中编写代码的人设计的,在这种环境中,额外的分配会产生不同的效果。StringReference类型的存在是为了简化这种情况(调用需要字符串参数但不希望分配和复制内存的API)。我确实理解StringReference
的用途,我只希望我可以使用它从组件检索字符串,尽可能高效地将字符串传递给组件。非常感谢你给出了一个明确的答案,目前这是不可能的,我只是想弄明白为什么。这是技术问题还是设计决策?只是因为返回引用可能更危险吗?它还不值得花时间优化吗?至少对于C++/CX组件的C++/CX调用来说,这似乎在技术上是可行的,而其他投影可以继续复制字符串。这是一个技术原因——StringReference不分配内存,也不拥有它引用的内存。相反,它获取另一个对象(在您的示例中为std::wstring对象)拥有的内存,并将其呈现给另一个函数。该内存的生命周期管理仍由所属对象负责。同样,如果您能够返回StringReference,那么当std::wstring超出范围时,内存将被释放。如果您想要可以返回的字符串值,请使用Platform::string,它管理自己内存的生存期。请记住,Platform::StringReference是WindowsCreateStringReference()的包装器,可以使用它来管理这样的引用类。是的,我知道我的示例通过返回释放的内存做了坏事,但这是我确认复制正在发生的一种方式。我确实有一个真正的用例