Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++/CX:为什么';返回一个StringReference工作是否像传递一个参数一样?_String_Windows Runtime_C++ Cx - Fatal编程技术网

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()的包装器,可以使用它来管理这样的引用类。是的,我知道我的示例通过返回释放的内存做了坏事,但这是我确认复制正在发生的一种方式。我确实有一个真正的用例