如何对抛出哪个标准异常做出明智的决定
How to make an intelligent decision about which standard exception to throw?
我们知道异常类有两个派生类:logic_error和runtime_error。
logic_error有四个派生类:domain_error、invalid_argument、length_error和out_of_range。
runtime_error有三个派生类:range_error、overflow_error和underflow_error。
虽然其中一些是不言自明的,如overflow_error和underflow_error,有些不是那么清楚,特别是range_error,无论是MSDN和cplusplus只是说"报告范围错误",这是接近说什么,它是如何不同的out_of_range和domain_error??
另一个问题是当我抛出异常时,我应该选择哪一个?例如,在reverse_string(char* s)中,当s为NULL时抛出哪个异常?在float calc_ellipse_area(float a, float b),当a或b是<=0时抛出?当a == b(严格地说,圆不是椭圆!)
最后,实际上,如果我抛出一个没有正确分类的异常真的有关系吗?
逻辑错误(理论上)是程序员错误的结果。运行时错误是程序员不容易避免的。
当你编写一个函数时,记录它的先决条件和/或假设是很有用的。如果这些前提条件被打破,这就是一个逻辑错误。
运行时错误通常是由外部原因引起的:文件操作失败,打印机脱机,无法加载DLL。
如果一个路径参数是错误的,这是一个逻辑错误。如果它是一个有效的路径字符串,但不存在,或者您没有访问它的权限,那将是一个运行时错误。
有时它变得武断。错误的用户输入可能是运行时错误,但未能验证用户输入更多的是逻辑错误。在特定的情况下,这可能并不明显。
如果某事开始于2011年2月1日,结束日期"01 Jan 2011"是无效参数,而"31 Feb 2011"则超出范围。"炸鱼薯条"的完成日期是一个域错误。长度错误通常与缓冲区大小有关,但也可能包括输入数据过多或过少或诸如此类的错误。
范围错误类似于超出范围错误,除了上下文(运行时,而不是逻辑)。例:可用打印机数量= 0。溢出和下溢或多或少是不言自明的。
最后,以你和你的同事觉得有意义的方式使用它们——或者根本不使用它们。有些人在所有情况下都使用std::exception
只有当你打算以不同的方式处理不同的异常时,这才是真正重要的。如果您只是打算显示(或记录)一条消息并继续,那么使用什么异常并不重要。
例如,在reverse_string(char* s)中,当s为NULL时抛出哪个异常?
在float calc_ellipse_area(float a, float b)中,当a或b是<=0时抛出哪个?当a == b(严格地说,圆不是椭圆!)
对于这两个,使用std::invalid_argument
。
或者您可以定义自己的异常,称为null_argument
,从std::logic_error
(或从std::invalid_argument
)派生,并将其用于NULL
参数。
例如,如果您想在遇到无效索引时抛出异常,那么您可以使用std::out_of_range
或定义从std::out_of_range
派生的更具体的类index_out_of_range
。
如果我抛出一个没有正确分类的异常真的重要吗?
是的,这很重要。例如,它增加了代码的可读性。如果在遇到无效索引时抛出std::logic_error
,那么它不会增加多少可读性,但是如果抛出std::out_of_range
,则会大大提高可读性。如果你输入index_out_of_range
,它会增加更多,因为它更具体。
out_of_range和range_error的区别在它们的父类的描述中:
logic_error:该类定义要报告的异常抛出对象的类型程序的内部逻辑错误。这些都是理论上的可以预防的。
runtime_error:该类定义要报告的异常抛出对象的类型只能在运行时确定的错误。
域误差是专门针对数学函数的。所以你的calc_ellipse_area可以在负值时抛出一个域错误(如果一个或两个参数都是0,则返回0)。如果椭圆碰巧也是一个圆,我没有任何理由抱怨,就像矩形面积函数在正方形上失败一样。
将null指针传递给不应该接收null的函数,我将通过无效参数异常处理。
c++允许你抛出任何你喜欢的东西。对于那些可能使用您的代码的人来说,真正有帮助的是,您在方法签名之后命名您抛出的内容,并且这些名称具有合理的描述性。默认情况下,函数可以抛出任何东西——为了保证函数不会抛出,你必须在签名中使用空的throw()。
- 标准c++库提供了用于报告c++程序中某些错误的类(17.6.5.12)。在这些类反映的错误模型中,错误分为两大类:逻辑错误和运行时错误。
- 逻辑错误的区别特征是它们是由于程序内部逻辑的错误造成的。理论上,它们是可以预防的。
相比之下,运行时错误是由超出程序范围的事件引起的。它们无法轻易提前预测。
然而,所有来自runtime_error
的异常类型都被错误分类——它们都很容易预防。
对于实际的运行时错误,c++标准库是相当不一致的,它有时使用返回值或内部状态(例如iostream::bad()
)。当它确实使用异常时,它们不会从runtime_error
派生。例如,std::bad_alloc
是std::exception
的直接子类。
总之,您不应该使用std::runtime_error
或其任何预定义的子类。
- 处理多个异常集合的C++方法
- 我在c++代码中生成了一个运行时#3异常
- 孤立代码块在结构中引发异常
- C++中的赋值发生,尽管右侧出现异常
- 从构造函数抛出异常时如何克服内存泄漏
- 异常属于C++中的线程还是进程
- 当类定义不可见时捕获异常
- 在决定是通过参考还是通过价值时,尺寸真的是一个问题吗
- 引发异常:读取访问冲突**dynamicArray**为0x1118235.发生
- 为什么异常不退出程序?
- 为什么我应该在异常处理中使用std::cerr而不是std::cout
- 如何修复链表类实现的未处理异常0xDDDDDDDD
- 关于:C++中异常对象的范围:为什么我没有得到副本?
- 是什么导致了Unity 3D中的"错误线程异常"?
- 如何将strftime中的格式错误作为异常捕获
- 创建具有 new in 函数和"this is nullptr"异常的对象
- GCC (libstdc++) 运行时如何在异常处于活动状态时决定终止 ()
- 未决定是使用异常还是报告错误消息
- 捕获异常后无法决定要打印的消息
- 如何对抛出哪个标准异常做出明智的决定