我是 C# 程序员,但现在我想更深入地了解 C++。
我知道 C++ 的基础知识,但我不知道如何处理错误。
例如:我正在写一个库。我创建了一个构造函数,它请求一个整数作为参数。
如果该整数大于 50,则为错误。在 C# 中我会抛出ArgumentOutOfRange
异常,但在 C++ 中我应该做什么?
我是 C# 程序员,但现在我想更深入地了解 C++。
我知道 C++ 的基础知识,但我不知道如何处理错误。
例如:我正在写一个库。我创建了一个构造函数,它请求一个整数作为参数。
如果该整数大于 50,则为错误。在 C# 中我会抛出ArgumentOutOfRange
异常,但在 C++ 中我应该做什么?
在 C# 中我会抛出 ArgumentOutOfRange 异常,但我应该在 C++ 中做什么?
首先,您应该考虑这是否不应该是您的函数的先决条件,将检查值是否在范围内的责任留给调用者。
如果您决定使用此选项,那么使用超出范围的值调用函数将是未定义的行为,并且在函数内部您可以有一个调试断言来帮助您发现可能的误用 - 而无需抛出任何异常。
另一方面,如果您决定该函数应该有一个广泛的合同,并通过在参数超出允许范围时抛出异常以明确定义的方式做出反应,那么您可以抛出std::out_of_range
异常。
例如:我正在写一个库 [...]
如果您正在编写一个库,这意味着您不知道客户在性能和健壮性方面的确切要求,您可以考虑提供两个这样的函数 - 一个是抛出异常的宽合约,另一个是抛出异常的窄合约假设客户提供有意义的输入。
这样,库的用户可以根据他们的用例决定是否可以支付每次调用函数时检查输入正确性的开销。
例如,这是 C++ 标准库为 所采用的策略std::vector
,它提供了一个非抛出operator[]
的窄协定,用于基于索引访问集合的元素(如果索引超出 - 此函数具有未定义的行为) bounds),以及at()
执行索引检查并在索引超出范围时抛出异常的成员函数。
这取决于是否可以将大于 50 的整数作为正常程序流的一部分传递给构造函数,或者这是否是异常情况。但一般来说,使对象构造失败的唯一方法是抛出异常。
您的用户代码可能如下所示:
int n = parse_user_input()
if (n < 50)
{
Foo x(n);
x.do_cool_stuff();
}
else
{
// report user error
}
也就是说,您实际上并没有对正常的控制流使用异常。使用这种代码模式,Foo::Foo(int)
如果参数超出范围,抛出异常是完全可以的。
您可以在 中找到有用的标准异常类<stdexcept>
。
与 C# 中的相同:抛出异常。这是防止对象被构造的唯一方法。
std::invalid_argument
关于扔什么是一个很好的标准选择。
来自 C++ FAQ:[17.8] 如何处理失败的构造函数?
摘抄:
抛出异常。
构造函数没有返回类型,因此不可能使用返回码。因此,发出构造函数失败信号的最佳方法是抛出异常。如果您没有使用异常的选项,“最坏”的解决方法是通过设置内部状态位将对象置于“僵尸”状态,这样对象的行为就好像它已经死了,即使它是技术上还活着。
因此,对于您的情况,投掷std::invalid_argument
orstd::out_of_range
是完全可以接受的。如果这对您的情况有益,您也可以抛出自定义异常。在 C++ 常见问题解答中,请参阅:[17.12] 我应该扔什么?