是在传递给库函数之前检查值更好,还是捕获抛出的异常更好

Is it better to check values before passing to a library function, or catch a thrown exception?

本文关键字:更好 异常 库函数 检查      更新时间:2023-10-16

假设我正在使用一个库,该库具有一个接受字符串参数的函数to_int。如果字符串是数字的字符表示,则此函数返回int,例如"23"将返回23。如果字符串不是数字,它将抛出一个std::runtime_error。更好的做法是:

if(is_all_digits(str))
    x = to_int(str);
else
    output("not an int, idiot. Try again");

try 
{
    x = to_int(str);
}
catch(...)
{
    output("not an int, idiot. Try again");
}

有几种不同的错误处理技术,每种技术都有优缺点。

让我们考虑一个函数getAllElements(),它获取一个包含一些元素的容器。

现在,这可能会产生一个错误(数据库连接或其他什么(。您现在可以选择

Errorcode getAllElements(std::vector<...> & cont);

std::vector<...> getAllElements(); //throws exceptions

这通常是一个一般的设计问题,取决于具体情况。出于多种原因,我更喜欢有例外的那一种。我可以分配,不需要预先确定的容器

auto elements = getAllElements();

下一件事是你将在哪里处理你的错误?如果像上面堆栈中的5个函数那样处理它们,那么每次都必须检查错误代码,并将其提供给下一个函数。异常将自动传播,直到有人发现并能够处理它


不过,例外情况也有一些不利之处。它们会导致更大的二进制文件,并且在抛出异常时速度较慢。在游戏开发中,通常不会因为这一点而使用任何例外(请收听以下内容了解更多信息:http://cppcast.com/2016/10/guy-davidson/他们讨论了为什么不使用异常。不过,我目前没有时间戳。(

在特殊情况下也应使用例外情况。你不能立即处理错误,必须在更高的地方处理。


因此,如果您不需要高性能/小二进制文件,我建议在有用的地方使用异常。它们可能导致键入更少的代码(如检查返回代码(,从而减少引入错误的位置。

以下也是关于CppCon 2016错误处理机制的一个很好的讨论:CppCon 2016:Patrice Roy"异常情况">

这个问题没有单一的答案,因为它取决于程序作为一个整体如何处理错误输入,以及在检测到错误时是否能够合理地恢复(无论这些错误是使用返回码还是通过抛出异常报告的(。

每个调用to_int()的函数都能立即从错误输入中恢复吗?如果没有,最好允许抛出异常。。。。因此它展开堆栈,直到有某个调用者(具有try/catch块(可以从错误中恢复为止。

如果您有许多调用to_int()的函数,您想对每个函数进行检查吗?如果是这样,就会导致大量的代码重复。

如果您有一个调用to_int()的函数,它可以立即从错误中恢复,而其他函数则不能?

如果您想向调用者报告错误(例如,允许比编写错误字符串更实质的内容(,该怎么办?

什么是没有is_all_digits()功能的?如果没有,如果您以错过to_int()将检测到的一些错误的方式实现它,该怎么办?然后你就有了两个世界中最糟糕的一个——做错误检查试图防止抛出异常,但函数无论如何都会抛出异常。例如,可能有一些全局设置导致to_int()只接受八进制数字(在07的范围内(,但is_all_digits()函数认为所有十进制数字都是有效的。

更一般地说,真正的需要是定义一个适用于整个程序的错误处理策略。试图根据单个函数的使用情况来决定是抛出异常还是不抛出异常,这完全没有意义。

如果您的程序使用异常报告错误是有意义的(例如,在main()中有一个集中的try/catch块,因此所有错误都会传播到调用堆栈上,因此main()会全局实现恢复(,那么抛出异常。如果程序中的每个函数都能检测到错误并在现场静默处理,那么就避免出现异常。

我提倡的是让狗(你的程序(摇尾巴(关于如何处理错误的低级决策(。你的问题本质上是问让尾巴摇狗是否合适。

如果捕获的异常确实是特定的,那么您可以使用特定的try-catch(使用通用try-catch不是一个好主意,因为您隐藏了一堆其他可能的错误(

一般来说,我倾向于在将字符串传递给函数之前检查它。

当您使用库或API时,您希望它能防止您的错误使用和其他错误。

函数的作用是控制给定参数的完整性,并引发异常。

请注意,在开发代码时也可以使用断言,然后在二进制产品中禁用断言。