简体   繁体   English

我应该抛出异常吗?

[英]Should I throw an exception

I am C# programmer but now I want to get more into C++. 我是C#程序员,但现在我想进一步学习C ++。
I know the basics of C++ but I don't know how to handle errors. 我知道C ++的基础知识,但我不知道如何处理错误。

For example: I am writing a library. 例如:我正在写一个库。 I create an constructor which requests an integer as an argument. 我创建了一个构造函数,它请求一个整数作为参数。
If that integer is bigger than 50, it is an error. 如果该整数大于50,则表示错误。 In C# I would throw an ArgumentOutOfRange exception, but what should I do in C++? 在C#中我会抛出一个ArgumentOutOfRange异常,但是我应该在C ++中做些什么呢?

In C# I would throw an ArgumentOutOfRange exception but what should I do in c++? 在C#中我会抛出一个ArgumentOutOfRange异常但是我应该在c ++中做什么?

First you should consider if that should not be a precondition of your function, leaving the responsibility of checking whether the value is in range to the caller. 首先,你应该考虑这是否应该是你的功能的前提条件 ,让责任检查值是否在调用者的范围内。

If you decide for this option, then invoking the function with an out-of-range value would be undefined behavior, and inside the function you could just have a debug assertion to help you spot possible misuses - without the need of throwing any exception. 如果您决定使用此选项,则调用具有超出范围值的函数将是未定义的行为,并且在函数内部您可以使用调试断言来帮助您发现可能的错误 - 无需抛出任何异常。

If you decide that the function should have a wide contract, on the other hand, and react in a well-defined way by throwing an exception when the argument is outside the permitted range, then you could throw an std::out_of_range exception. 另一方面,如果您决定该函数应该具有宽泛的契约,并且当参数超出允许范围时通过抛出异常以明确定义的方式做出反应,那么您可以抛出std::out_of_range异常。

For example: I am writing a libary [...] 例如:我正在写一个图书馆[...]

If you are writing a library, meaning that you do not know the exact requirements of your clients in terms of performance and robustness, you may consider providing two such functions - one with a wide contract that throws exceptions, and one with a narrow contract that assumes the client provides meaningful input. 如果您正在编写库,这意味着您不了解客户在性能和稳健性方面的确切要求,您可以考虑提供两个这样的功能 - 一个具有抛出异常的广泛合同,另一个具有狭窄的合同,假设客户提供有意义的输入。

This way, the user of your library could decide based on their use cases whether or not it is OK to pay for the overhead of checking the correctness of the input each time your function is called. 这样,您的库的用户可以根据他们的用例决定是否可以支付每次调用函数时检查输入正确性的开销。

This is, for instance, the strategy adopted by the C++ Standard Library for std::vector , which provides a non-throwing operator[] with a narrow contract for accessing elements of the collection based on the index (this function has undefined behavior if the index is out-of-bounds), and a member function at() that performs index checking and throws an exception if the index is out-of-bounds. 例如,这是C ++标准库为std::vector采用的策略,它提供了一个非抛出的operator[]具有一个狭义的契约,用于根据索引访问集合的元素(如果此函数具有未定义的行为,则如果索引超出范围,则at()的成员函数执行索引检查并抛出异常。

It depends on whether an integer larger than 50 could possibly be passed to the constructor as part of normal program flow, or whether that's an exceptional condition. 它取决于是否可能将大于50的整数作为正常程序流的一部分传递给构造函数,或者这是否是异常条件。 But in general the only way to have object construction fail is by throwing an exception. 但总的来说,使对象构造失败的唯一方法是抛出异常。

Your user code might look like this: 您的用户代码可能如下所示:

int n = parse_user_input()

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

That is, you don't actually use exceptions for normal control flow. 也就是说,您实际上并没有使用异常来进行正常的控制流程。 With that sort of code pattern, it would be perfectly fine for Foo::Foo(int) to throw an exception if the argument were out of range. 有了这种代码模式,如果参数超出范围, Foo::Foo(int)就会抛出异常。

You can find useful standard exception classes in <stdexcept> . 您可以在<stdexcept>找到有用的标准异常类。

The same thing as in C#: throw an exception. 与C#中的相同:抛出异常。 This is the only way to prevent an object from being constructed. 这是防止构造对象的唯一方法。

std::invalid_argument is a good standard choice regarding what to throw. std::invalid_argument是关于扔什么的一个很好的标准选择。

From the C++ FAQ: [17.8] How can I handle a constructor that fails? 从C ++ FAQ: [17.8]如何处理失败的构造函数?

Excerpt: 摘抄:

Throw an exception. 抛出一个例外。

Constructors don't have a return type, so it's not possible to use return codes. 构造函数没有返回类型,因此无法使用返回代码。 The best way to signal constructor failure is therefore to throw an exception. 因此,表示构造函数失败的最佳方法是抛出异常。 If you don't have the option of using exceptions, the "least bad" work-around is to put the object into a "zombie" state by setting an internal status bit so the object acts sort of like it's dead even though it is technically still alive. 如果您没有使用异常的选项,那么“最不好”的解决方法是通过设置内部状态位将对象置于“僵尸”状态,这样对象的行为有点像死了,即使它是技术上还活着。

So, throwing std::invalid_argument or std::out_of_range would be perfectly acceptable for your situation. 因此,抛出std::invalid_argumentstd::out_of_range对于你的情况是完全可以接受的。 You could also throw a custom exception if that would be beneficial in your situation. 如果这对您的情况有益,您也可以抛出自定义异常 In the C++ FAQ see: [17.12] What should I throw? 在C ++常见问题中,请参阅: [17.12]我应该扔什么?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM