字符串 (C++/CX)

Windows 运行时中的文本由 Platform::String 类以 C++/CX 表示。 当来回向 Windows 运行时类中的方法传递字符串或者跨越应用程序二进制接口 (ABI) 边界与其他 Windows 运行时组件交互时,请使用 Platform::String Class。 虽然 Platform::String Class 为几种常见字符串操作提供方法,但它还不是全功能字符串类。 在您的 C++ 模块中,将标准 C++ 字符串类型(如 wstring )用于任何大量的文本处理,然后将最终结果转换为 Platform::String^ ,最后再向(或从)公共接口传递它。 在 wstringwchar_t*Platform::String之间进行转换很容易也很有效。

快速传递

在某些情况下,编译器可以验证它能否安全地构造 Platform::String 或将 String 传递到一个函数而无需复制基础字符串数据。 此类操作称为 快速传递 ,它们以透明方式发生。

字符串构造

String 对象的值是 char16 (16 位 Unicode)字符的不可变(只读)序列。 由于 String 对象是不可变的,因此将新字符串文本分配给 String 变量其实就是用新的 String 对象替换原始 String 对象。 串联运算涉及析构原始 String 对象和创建新对象。

文字

一个 文本字符 就是用单引号括起来的一个字符,一个 文本字符串 就是用双引号括起来的一个字符序列。 如果使用文本初始化 String^ 变量,则编译器假定文本由 char16 字符组成。 也就是说,在 _T()TEXT() 宏中,不必在文本前加上字符串修饰符“L”或用引号将文本括起来。 有关 Unicode 的 C++ 支持的更多信息,请参见 Unicode Programming Summary

下面的示例演示用来构造 String 对象的各种方法。

// Initializing a String^ by using string literals
String^ str1 = "Test"; // ok for ANSI text only. uses current code page
String^ str2("Test");
String^ str3 = L"Test";
String^ str4(L"Test");


//Initialize a String^ by using another String^
String^ str6(str1);
auto str7 = str2;

// Initialize a String from wchar_t* and wstring
wchar_t msg[] = L"Test";
String^ str8 = ref new String(msg);
std::wstring wstr1(L"Test");
String^ str9 = ref new String(wstr1.c_str());
String^ str10 = ref new String(wstr1.c_str(), wstr1.length());

字符串处理操作

String 类为连接、比较字符串和其他基本字符串操作提供方法和运算符。 若要执行更广泛的字符串操作,请使用 String::Data() 成员函数来检索 String^ 对象的值作为 const wchar_t*。 然后使用该值初始化 std::wstring,后者提供丰富的字符串处理函数。


 // Concatenation 
 auto str1 = "Hello" + " World";
 auto str2 = str1 + " from C++/CX!";    
 auto str3 = String::Concat(str2, " and the String class");
 
 // Comparison
 if (str1 == str2) { /* ... */ }
 if (str1->Equals(str2)) { /* ... */ }
 if (str1 != str2) { /* ... */ }
 if (str1 < str2 || str1 > str2) { /* ... */};
 int result = String::CompareOrdinal(str1, str2);
 
 if(str1 == nullptr) { /* ...*/};
 if(str1->IsEmpty()) { /* ...*/};

// Accessing individual characters in a String^
 auto it = str1->Begin();
 char16 ch = it[0];

字符串转换

Platform::String 中只能包含 char16 字符或 NULL 字符。 如果应用程序必须使用 8 位字符,请使用 String::Data 提取文本作为 const wchar_t*。 然后,您可以使用适当的 Windows 函数或标准库函数对数据进行操作并将其转换回 wchar_t*wstring(用于构造新的 Platform::String表示。

下面的代码片段演示 String^ 变量和 wstring 变量间如何相互转换。 有关此示例中使用的字符串操作的更多信息,请参见 basic_string::replace

// Create a String^ variable statically or dynamically from a literal string. 
String^ str1 = "AAAAAAAA";

// Use the value of str1 to create the ws1 wstring variable.
std::wstring ws1( str1->Data() ); 
// The value of ws1 is L"AAAAAAAA".

// Manipulate the wstring value.
std::wstring replacement( L"BBB" );
ws1 = ws1.replace ( 1, 3, replacement );
// The value of ws1 is L"ABBBAAAA".

// Assign the modified wstring back to str1. 
str1 = ref new String( ws1.c_str() ); 

字符串长度和嵌入的 NULL 值

String::Length 返回字符串中的字符数目,而非字节数目。 当使用堆栈语义构造字符串时,一般不计算终止 NULL 字符,除非您明确指定。

Platform::String 可以包含嵌入的 NULL 值,但前提是 NULL 必须为串联运算的结果。 字符串文本中不支持嵌入的 NULL,因此,不能以这种方式使用嵌入的 NULL 初始化 Platform::String。 在显示该字符串时(例如,将字符串分配给 Platform::String 属性时),将忽略 TextBlock::Text 中嵌入的 NULL 值。 当字符串值由 Data 属性返回时,将删除嵌入的 NULL。

StringReference

有时,代码 (a) 接收 std::wstring、wchar_t 字符串或 L"" 字符串文本,并直接将其传递到采用 String^ 作为输入参数的另一个方法。 只要原始字符串缓冲区本身在函数返回之前保持有效且不发生变化,则可以将 wchar_t* 字符串或字符串文本转换为 Platform::StringReference,然后将其代替 Platform::String^传入。 之所以允许这样做,是因为 StringReference 具有用户定义的到 Platform::String^的转换。 通过使用 StringReference ,可避免创建字符串数据的额外副本。 在传递大量字符串的循环中或传递非常大的字符串时,可通过使用 StringReference显著提高潜在性能。 但是,由于 StringReference 实质上是借用原始字符串缓冲区,因此必须格外小心,以免损坏内存。 不应将 StringReference 传递给异步方法,除非可以保证原始字符串在该方法返回时处于范围之内。 如果发生第二个记录分配操作,从 StringReference 初始化的 String^ 将强制分配和复制字符串数据。 在此情况下, StringReference的性能优势将丧失。

请注意, StringReference 是标准的 C++ 类类型,而非 ref 类,不能用于您定义的 ref 类的公共接口。

下面的示例演示如何使用 StringReference:

void GetDecodedStrings(std::vector<std::wstring> strings)
{
    using namespace Windows::Security::Cryptography;
    using namespace Windows::Storage::Streams;

    for (auto&& s : strings)
    {
        // Method signature is IBuffer^ CryptographicBuffer::DecodeFromBase64String (Platform::String^)
        // Call using StringReference:
        IBuffer^ buffer = CryptographicBuffer::DecodeFromBase64String(StringReference(s.c_str()));

        //...do something with buffer
    }
}