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

时间:2016-10-18 08:31:00

标签: c++ exception-handling

假设我正在使用一个带有函数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");
}

4 个答案:

答案 0 :(得分:2)

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

让我们考虑一个函数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 “The Exception Situation"

答案 1 :(得分:1)

这个问题没有一个答案,因为它取决于整个程序如何处理错误输入,以及检测到错误时是否可以明智地恢复(无论是使用返回代码报告这些错误还是抛出异常)。

每个调用to_int()的函数都可以立即从错误的输入中恢复吗?如果没有,最好允许抛出异常....所以它会解除堆栈,直到有一些调用者(带有try/catch块)可以实际从错误中恢复。

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

如果你有一些调用to_int()的函数可以立即从错误中恢复而其他一些函数不可以恢复怎么办?

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

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

更一般地说,真正需要的是定义一个适用于整个程序的错误处理策略。试图根据单个函数的用法决定抛出异常或不抛出异常,这完全忽略了这一点。

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

我所倡导的是允许狗(你的程序)摇尾巴(关于如何处理错误的低级决策)。你的问题基本上是要让尾巴摇尾巴是否合适。

答案 2 :(得分:0)

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

一般来说,我的首选是在将字符串传递给函数之前检查字符串。

答案 3 :(得分:0)

当您使用库或API时,您希望它可以防止您使用不良和其他错误。

这是你的函数控制给定参数的完整性和抛出异常的角色。

请注意,您还可以在开发代码时使用断言,然后禁用它以进行二进制生成。