如何让wstring_convert::to_bytes抛出range_error异常?

How can I get wstring_convert::to_bytes to throw a range_error exception?

本文关键字:range 抛出 error 异常 bytes to wstring convert      更新时间:2023-10-16

我使用std::wstring_convert将wstring转换为多字节字符串,如下所示:

    // convert from wide char to multibyte char
    try
    {
        return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(wideMessage);
    }
    // thrown by std::wstring_convert.to_bytes() for bad conversions
    catch (std::range_error& exception)
    {
        // do something...
    }

为了单元测试块,我已经注释为do something...,我希望传递一个将抛出std::range_error异常的wstring。

然而,我还没有能够表述这样一个将失败这样的转换的wstring。wstring将使用UTF16,我一直在阅读有关高低代理的内容。例如,后跟"b"的UTF16字符D800应该是无效的。std::wstring(L"xd800b");编译失败的原因可能是相同的。如果我创建一个像下面这样的wstring,它将不会在转换时抛出异常:

std::wstring wideMessage(L" b");
wideMessage[0] = L'xd800';
// doesn't throw
std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(wideMessage);

是否有一个合适的wstring我可以用来在转换期间抛出异常?

我试过5.1,5.2和5.3从这个链接。我使用的是Visual Studio 2015.

Microsoft的std::codecvt_utf8实现似乎成功地将任何UTF-16代码单元转换为utf -8,包括代理对。这是一个bug,因为代理不可编码。libc++ (LLVM)和libstdc++ (GCC)都将正确抛出std::range_error,并且无法转换未配对的代理。

查看他们的代码,似乎它抛出的唯一方式是如果一个字符大于该facet的Maxcode模板参数。例如:

std::wstring_convert<std::codecvt_utf8<wchar_t, 0x1>>

正如所指出的—— (已接受的答案)微软的codecvt_utf8实现似乎存在bug。

我知道我正在处理的字符串总是UTF16,我想转换为UTF8。我最终改变了实现如下:

    // convert from wide char to multibyte char
    try
    {
        return std::wstring_convert<std::codecvt_utf8_utf16 <wchar_t>>().to_bytes(wideMessage);
    }
    // thrown by std::wstring_convert.to_bytes() for bad conversions
    catch (const std::range_error & exception)
    {
        // do something...
    }

下面的语句现在可以正确抛出:

std::wstring wideMessage(L" b");
wideMessage[0] = L'xd800';
// throw std::range_error
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(wideMessage);

如果没有单元测试,我永远不会发现这个bug !