C++/CX: Why doesn't returning a StringReference work like passing one as an argument?

StackOverflow https://stackoverflow.com/questions/17727524

  •  03-06-2022
  •  | 
  •  

سؤال

Platform::StringReference exists so that you can pass a const wchar_t* across the ABI boundary to a function accepting a String^ without making a copy. The StringReference implicitly converts to a String^ whose internal pointer matches the original const wchar_t*. This is verified by the following code; if you step through it you find that 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));
}

However, trying to return a StringReference doesn't seem to work the same way and I'm curious why. If I have a function that returns String^ and I return a StringReference from it then the same implicit conversion operator is called, but when the caller gets their String^ it has a different internal data pointer that contains a copy. Here's some code that tries it:

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();
}

That code verifies in two ways: first, if you step through you'll find that z != rz and second, r ends up pointing to a valid string rather than garbage, so a copy must have been made because the original string is freed at the end of ret.

I also tried returning via out parameter, but I get the same results as a straight return (z != oz and o ends up with a valid string):

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();
}

Is there a way to return a StringReference across the ABI boundary in the same way that you can pass one? I imagine the behavior would depend on the language of the caller and how that language marshals strings from WinRT, but it seems like at least a C++/CX caller ought to be able to do it.

هل كانت مفيدة؟

المحلول

No you can't return a StringReference across the ABI boundary. Returning a StringReference across the ABI boundary is similar (but not identical) to returning the address of a local variable. That's because the whole point of a StringReference is that the StringReference doesn't allocate any new memory.

Consider what would happen if you could return a StringReference across the ABI boundary. What would happen if you had:

String^ ReturnAString()
{
    const wchar_t buffer[500] = "MyString";
    return StringReference(buffer);
}

The StringReference is just a wrapper around the stack allocated buffer. And clearly you can't return that across the ABI boundary (the stack storage is reclaimed as soon as the routine exits).

Instead you need to return a real Platform::String - a Platform::String contains a copy of the string data and thus it can safely be returned to the caller.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top