在编写一个函数以在不同编码的字符串之间进行转换(例如从UTF-8到UTF-16),处理错误的最佳方法是什么(例如,无效输入UTF-8字节序列)?抛出异常或返回错误代码(甚至是bool
)?
// Throws a C++ exception on error.
std::wstring ConvertFromUtf8ToUtf16(const std::string& utf8);
// Returns true on success, false on error.
bool ConvertFromUtf8ToUtf16(std::wstring& utf16, const std::string& utf8);
使用异常,可以进行链式函数调用(当函数返回值用作其他函数/方法的输入时)。
但我不确定在这种情况下使用例外情况是否合适;我在考虑Eric Lippert in his quality blog post所谓的烦恼异常(以及相关的Int32.Parse()/TryParse()
示例)。
例如,如果使用了异常,则应强制调用者将函数调用包装在try/catch
块中以检查无效UTF-8输入的情况:
try
{
wstring utf16 = ConvertFromUtf8ToUtf16(utf8);
}
catch(const Utf8ConversionException& e)
{
// Bad UTF-8 byte sequence
...
}
这对我来说似乎并不理想。
也许最好的办法就是只提供两个重载(在非投掷重载中实现转换代码,在throw过载中调用非投掷版本,以防万一)错误返回代码抛出异常)?
答案 0 :(得分:2)
一个指导原则是考虑如果用户忽略或不知道他们应该检查您返回的错误代码会发生什么。
第三个可能的选择在某种程度上平衡了错误代码的简洁性并迫使程序员意识到潜在的错误,这使得该函数需要引用错误代码。这也适用于导出的库和(大多数较旧的)编译器,它们不能有效地处理异常。
StringConversionResult result; // Could be a "success" bool
wstring utf16 = ConvertFromUtf8ToUtf16(utf8, result);
答案 1 :(得分:0)
如果从库中导出此函数,请使用返回码。当使用不同的C / C ++运行时库构建库和客户端时,从导出的函数中抛出异常可能会导致程序崩溃。通常,这是未定义的行为。
对于内部使用,我相信,例外是一个更好的选择。你正在谈论的情况,当调用者不使用catch块时,立即崩溃程序(未处理的异常)。这样做会更好,然后在未来的某个时间点继续执行程序并使用未定义的结果。
答案 2 :(得分:0)
只有三种选择。第一个是“通过错误代码点替换所有失败” - Unicode标准提供了几个替换代码点。在某些情况下这很好。第二是抛出异常。第三是提供一个错误函数对象,在失败时调用。例如,
bool fail = false;
std::u16string str = ConvertFromUTF8ToUTF16(utf8, [&] {
return u16"default";
// or
throw std::runtime_error("fail");
// or
fail = true;
});
关键在于,在任何情况下,您都不依赖于用户检查失败 - 如果他什么都不做,那么他的功能不会继续,编译器会哭,或者该功能可以继续。
返回错误代码不是一个选项 - 这很容易出错。