1

在编写一个函数来在不同编码的字符串之间进行转换(例如从 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在他的质量博客文章中所说的令人烦恼的异常(以及相关Int32.Parse()/TryParse()示例)。

例如,如果使用异常,则应强制调用者将函数调用包装在try/catch块中以检查无效 UTF-8 输入的大小写:

try
{
   wstring utf16 = ConvertFromUtf8ToUtf16(utf8);
}
catch(const Utf8ConversionException& e)
{
   // Bad UTF-8 byte sequence
   ...
}

这对我来说似乎并不理想。

也许最好的办法是只提供两个重载(在非抛出重载中实现转换代码,在抛出重载中只调用非抛出版本,并在错误返回代码的情况下抛出异常)?

4

3 回答 3

2

一个指导方针是考虑如果用户忽略不知道他们应该检查您返回的错误代码会发生什么。

  • 如果代码理论上可以在遇到错误时继续运行,则返回错误可能被认为是合理的。正如你提到的,代码看起来更干净。
  • 如果忽略错误可能会导致以后出现非常糟糕的行为,那么抛出异常可能是一个更好的主意。
  • 第三种可能的选择在某种程度上平衡了错误代码的简洁性并迫使程序员意识到潜在的错误是使函数需要对错误代码的引用。这在导出的库和不能有效处理异常的(大多数较旧的)编译器中也可以很好地工作。

    StringConversionResult result; // Could be a "success" bool

    wstring utf16 = ConvertFromUtf8ToUtf16(utf8, result);

于 2012-09-15T15:44:59.237 回答
0

如果此函数是从库中导出的,请使用返回码。当库和客户端使用不同的 C/C++ 运行时库构建时,从导出的函数中抛出异常可能会使程序崩溃。通常,这是未定义的行为。

对于内部使用,我相信异常是更好的选择。您正在谈论的情况,当调用者不使用 catch 块时,程序会立即崩溃(未处理的异常)。这样会更好,然后在将来的某个时间点继续执行未定义结果的程序。

于 2012-09-15T15:49:07.623 回答
0

只有三个选择。第一个是“用错误代码点替换所有故障”——Unicode 标准提供了几个替换代码点。这在某些情况下很好。二是抛出异常。三是提供错误函数对象,失败时调用。例如,

bool fail = false;
std::u16string str = ConvertFromUTF8ToUTF16(utf8, [&] {
    return u16"default";
    // or
    throw std::runtime_error("fail");
    // or
    fail = true;
});

关键是,在任何情况下,您都不会依赖用户来检查故障——如果他什么都不做,那么要么他的函数不会继续,编译器会哭,要么函数可以继续。

返回错误代码不是一种选择——这很容易出错。

于 2012-09-15T15:52:02.643 回答