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

时间:2015-08-24 12:41:53

标签: c++ unit-testing unicode std visual-studio-2015

我正在使用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,我一直在阅读高低代理。例如,D800的UTF16字符后跟“b”应该无效。 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在转换过程中抛出异常吗?

我尝试过来自this link的5.1,5.2和5.3。我正在使用Visual Studio 2015。

2 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分:1)

正如一二三所指出的那样(已接受回答)微软对codecvt_utf8的实施似乎被窃听。

我知道我正在处理的字符串总是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);

如果没有单元测试,我就不会发现这个错误!