我应该抛出异常吗?

时间:2013-05-24 11:45:00

标签: c++ exception error-handling

我是C#程序员,但现在我想进一步学习C ++。
我知道C ++的基础知识,但我不知道如何处理错误。

例如:我正在写一个库。我创建了一个构造函数,它请求一个整数作为参数。
如果该整数大于50,则表示错误。 在C#中我会抛出一个ArgumentOutOfRange异常,但我应该怎么做C ++?

4 个答案:

答案 0 :(得分:21)

  

在C#中我会抛出一个ArgumentOutOfRange异常,但我该怎么做呢?

首先,您应该考虑这不应该是您的函数的前提条件,而是负责检查该值是否在调用者的范围内。

如果您决定使用此选项,则调用具有超出范围值的函数将是未定义的行为,并且在函数内部您可以使用调试断言来帮助您发现可能的错误 - 无需抛出任何例外。

另一方面,如果你决定该函数应该有一个广泛的契约,并且当参数超出允许范围时抛出异常,并以明确定义的方式做出反应,那么你可以抛出一个{{3}例外。

  

例如:我正在写一个图书馆[...]

如果您正在编写库,这意味着您不了解客户在性能和稳健性方面的确切要求,您可以考虑提供两个这样的功能 - 一个具有广泛合同的抛出异常,并且一个狭义的契约假定客户端提供有意义的输入。

这样,您的库的用户可以根据他们的用例决定是否可以支付每次调用函数时检查输入正确性的开销。

例如,这是C ++标准库为std::vector采用的策略,它提供了一个非投掷std::out_of_range,它具有根据索引访问集合元素的狭义契约(如果索引超出范围,则此函数具有未定义的行为;以及执行索引检查的成员函数operator[],如果索引超出范围,则抛出异常。

答案 1 :(得分:4)

这取决于是否可能将大于50的整数作为正常程序流的一部分传递给构造函数,或者这是否是异常条件。但总的来说,使对象构造失败的唯一方法是抛出异常。

您的用户代码可能如下所示:

int n = parse_user_input()

if (n < 50)
{
    Foo x(n);
    x.do_cool_stuff();
}
else
{
    // report user error
}

也就是说,您实际上并没有使用异常来进行正常的控制流程。使用这种代码模式,如果参数超出范围,Foo::Foo(int)抛出异常将是完全正常的。

您可以在<stdexcept>中找到有用的标准例外类。

答案 2 :(得分:3)

与C#中的相同:抛出异常。这是防止构造对象的唯一方法。

std::invalid_argument是关于扔什么的一个很好的标准选择。

答案 3 :(得分:0)

来自C ++ FAQ:[17.8] How can I handle a constructor that fails?

摘录:

  

抛出异常。

     

构造函数没有返回类型,因此无法使用   返回码。因此,表示构造函数失败的最佳方法   抛出异常。如果您没有使用选项   例外,“最不好”的解决方法是将对象放入   “僵尸”状态通过设置内部状态位使对象起作用   有点像它死了,即使它在技术上还活着。

因此,投掷std::invalid_argumentstd::out_of_range对您的情况完全可以接受。您也可以抛出自定义异常,如果这对您的情况有益。在C ++ FAQ中,请参阅:[17.12] What should I throw?