C++-异常处理中:logic_error、runtime_error
两者分别表示逻辑错误、运行时异常,这两种异常在我们自己的程序中,如果要做异常处理,具体应该用在什么地方、用在什么环境下呢?请高手解答,同时给出具体的应用实例。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
两者分别表示逻辑错误、运行时异常,这两种异常在我们自己的程序中,如果要做异常处理,具体应该用在什么地方、用在什么环境下呢?请高手解答,同时给出具体的应用实例。
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(4)
logic_error 逻辑错误:也称句法错误,这是一种会导致运行出错,但并不会崩溃。
它会让程序产生意外的行为,但可能不会让人迅速的察觉到
因为逻辑错误不会让程序崩溃,它只是走错了路
在编译型和解释型语言中,都会有逻辑错误,与语法错误的区别在于,它是可以通过编译的,只是运行的方式出乎人的意料
常常是因为粗心引起的
有的编译在,也会在编译时期就指出一些潜在的逻辑错误
runtime_error 运行时错误:它发生在程序的运行阶段,与此相反的是编译时错误
运行时错误是程序员们可能预料到,但是,又没法直接解决的问题,如果,内存用完了导致无法再分配。
而这种情况下,只有在运行时才会发生的,编译时不可能被检测到
异常处理可以捕抓大部分的运行时错误
C++语言本身或标准程序库所抛出的所有异常,都派生自基类exception。这是其他数个标准异常类别的基类,它们共同构成一个类体系:
这些标准异常类别分为三组:
(1)语言本身所支持的异常
此类异常用以支撑某些语言特性。主要包括:
bad_alloc:new操作失败会抛出。
bad_cast:执行期间加在一个引用上面的动态性型别转换操作失败时抛出。
bad_typeid:执行RTTI时,交给typeid的参数为零或空指针时抛出
bad_exception:非预期的异常
(2)C++标准程序库发出的异常
总是派生自logic_error。逻辑错误是由于程序内部逻辑而导致的错误。逻辑错误是可以避免的,且在程序开始执行之前,能够被检测到。
C++标准库中定义的逻辑错误如下:
class logic_error : public exception {
public:
explicit logic_error (const string& what_arg);
};
class invalid_argument : public logic_error {
public:
explicit invalid_argument (const string& what_arg);
};
class out_of_range : public logic_error {
public:
explicit out_of_range (const string& what_arg);
};
class length_error : public logic_error {
public:
explicit length_error (const string& what_arg);
};
class domain_error : public logic_error {
public:
explicit domain_error (const string& what_arg);
};
错误分类解释及举例:
domain_error:专业领域内的范畴
invalid_argument:无效参数,比如讲bitset以char而非0或1进行初始化
length_error:可能超越了最大极限,比如对着某个字符串附加太多字符。
out_of_range:参数不再预期范围内。例如在诸如array的容器或字符串string中采用一个错误索引。
(3)程序作用域之外发出的异常
总是派生自runtime_error,用来指出“不在程序范围内,且不容易回避”的事件。此类错误只在程序执行时才是可检测的。C++标准库中的定义如下:
class runtime_error : public exception {
public:
explicit runtime_error (const string& what_arg);
};
class range_error : public runtime_error {
public:
explicit range_error (const string& what_arg);
};
class overflow_error : public runtime_error {
public:
explicit overflow_error (const string& what_arg);
};
class underflow_error : public runtime_error {
public:
explicit underflow_error (const string& what_arg);
};
range_error:内部计算时发生区间错误
overflow_error:算数运算时发生上溢
underflow_error:算数运算时发生下溢
Update:
实例代码:
#include <iostream>
#include <string>
#include <bitset>
#include <typeinfo>
#include <vector>
#include <stdexcept>
using namespace std;
//自定义配置器,vector分配空间使用
template<class _Ty>
class stingyallocator : public allocator<_Ty>
{
public:
template <class U>
struct rebind {
typedef stingyallocator<U> other;
};
size_t max_size( ) const
{
return 10;
};
};
int main()
{
//逻辑错误:out_of_range
try {
string str( "Micro" );
string rstr( "soft" );
str.append( rstr, 5, 3 );
cout << str << endl;
}
catch ( exception &e ) {
cerr << "Caught: " << e.what( ) << endl;
cerr << "Type: " << typeid( e ).name( ) << endl << endl;
};
//逻辑错误:length_error
try
{
vector<int, stingyallocator< int > > myv;
for ( int i = 0; i < 11; i++ )
myv.push_back( i );
}
catch ( exception &e )
{
cerr << "Caught " << e.what( ) << endl;
cerr << "Type " << typeid( e ).name( ) << endl << endl;
};
//逻辑错误:invalid_argument
try
{
bitset< 32 > bitset( string( "11001010101100001b100101010110000") );
}
catch ( exception &e )
{
cerr << "Caught " << e.what( ) << endl;
cerr << "Type " << typeid( e ).name( ) << endl << endl;
};
//逻辑错误:domain_error
try
{
throw domain_error( "Your domain is in error!" );
}
catch (exception &e)
{
cerr << "Caught: " << e.what( ) << endl;
cerr << "Type: " << typeid(e).name( ) << endl << endl;
};
//运行时错误:range_error
try
{
throw range_error( "The range is in error!" );
}
catch (exception &e)
{
cerr << "Caught: " << e.what( ) << endl;
cerr << "Type: " << typeid( e ).name( ) << endl << endl << endl;
};
//运行时错误:underflow_error
try
{
throw underflow_error( "The number's a bit small, captain!" );
}
catch ( exception &e ) {
cerr << "Caught: " << e.what( ) << endl;
cerr << "Type: " << typeid( e ).name( ) << endl << endl;
};
//运行时错误:overflow_error
try
{
bitset< 33 > bitset;
bitset[32] = 1;
bitset[0] = 1;
unsigned long x = bitset.to_ulong( );
}
catch(exception &e)
{
cerr << "Caught " << e.what() << endl;
cerr << "Type: " << typeid(e).name() << endl << endl;
}
return 0;
}
运行结果:
推荐参考资料:
【1】《C++Primer(第三版)》第855页 19.2.8C++标准的异常类层次结构
【2】《C++标准程序库》第25页 3.3 错误处理和异常处理
【3】Confused about std::runtime_error vs. std::logic_error
【4】C++中异常类的使用方法
C++标准异常类的关系如下:基类是exception,他有4个派生类:bad_alloc,bad_cast,runtime_error,logic_error;
runtime_error有3个派生类:overflow_error、underflow_error、range_error;
logic_error有4个派生类:domain_error、invalid_argument、length_error以及out_of_range。
从它们派生类的命名可以大致了解到它们区别。
The standard describes logic_error as: "The class logic_error defines the type of objects thrown as exceptions to report errors presumably detectable before the program executes, such as violations of logical preconditions or class invariants."
By contrast, it describes runtime_error as: "The class runtime_error defines the type of objects thrown as exceptions to report errors presumably detectable only when the program executes." That seems to be a better fit.
参考链接:Confused about std::runtime_error vs. std::logic_error
关于runtime_error和logic_error的区别,C++标准中提到:
The class logic_error defines the type of objects thrown as exceptions to report errors presumably detectable before the program executes, such as violations of logical preconditions or class invariants.
The class runtime_error defines the type of objects thrown as exceptions to report errors presumably detectable only when the program executes
意思就是说:逻辑错误指的的是在程序执行前多半能推断出来,这里的推断指的应该是有的时候编译器能够指出部分的逻辑错误(以警告信息的方式),但是多半的逻辑错误要靠程序员自己来发现,典型的示例就是对某个程序片段应满足的前条件(precondition)的违背,或者违背了某些类的不变量的范围约束,给函数sqrt()传入负数出现的就是逻辑错误,违背了precondition。运行时错误指的的是只有当程序运行的过程中才能发现的错误。在程序运行之前看不出问题,例如栈的上溢和下溢,例如给std::exp()传入过大的参数,会产生溢出的错误,即属于运行时错误。
通常我们会想既然逻辑错误在运行之前就能发现,为什么不在运行之前就把它处理好呢? 程序员往往在开发阶段用assert来消除许多的逻辑错误。比较麻烦的情况是,当逻辑错误的种类太多太杂的时候,用代码不停地条件判断,而且有很多的逻辑错误很难发现(是人就会犯错:))。还不如直接抛出异常,通过异常处理来的直接简单。
关于各种runtime_error和logic_error错误的示例,微软的MSDN给出了一些简单的代码,查看这些代码可以有一些理性的认识。