C++异常处理:logic_error、runtime_error
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。
逻辑错误指的的是在程序执行前多半能推断出来,这里的推断指的应该是有的时候编译器能够指出部分的逻辑错误(以警告信息的方式),但是多半的逻辑错误要靠程序员自己来发现,典型的示例就是对某个程序片段应满足的前条件(precondition)的违背,或者违背了某些类的不变量的范围约束,给函数sqrt()传入负数出现的就是逻辑错误,违背了precondition。运行时错误指的的是只有当程序运行的过程中才能发现的错误。在程序运行之前看不出问题,例如栈的上溢和下溢,例如给std::exp()传入过大的参数,会产生溢出的错误,即属于运行时错误。
通常我们会想既然逻辑错误在运行之前就能发现,为什么不在运行之前就把它处理好呢? 程序员往往在开发阶段用assert来消除许多的逻辑错误。比较麻烦的情况是,当逻辑错误的种类太多太杂的时候,用代码不停地条件判断,而且有很多的逻辑错误很难发现(是人就会犯错:))。还不如直接抛出异常,通过异常处理来的直接简单。关于各种runtime_error和logic_error错误的示例,微软的MSDN给出了一些简单的代码,查看这些代码可以有一些理性的认识。
从它们派生类的命名可以大致了解到它们区别。
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:算数运算时发生下溢
实例代码:
#include
#include
#include
#include
#include
#include
using namespace std;
//自定义配置器,vector分配空间使用
template
class stingyallocator : public allocator<_Ty>
{
public:
template
struct rebind
{
typedef stingyallocator 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
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;
}
运行结果:
STD:逻辑错误::逻辑误差
纠错
(1)explicit logic_error( const std::string& what_arg );
(2)explicit logic_error( const char* what_arg );
(since C++11)
构造异常对象what_arg作为解释性字符串,可以通过what()...
因为复制std::exception不允许抛出异常,此消息通常作为单独分配的引用计数字符串存储在内部。这也是为什么没有构造函数std::string&&::无论如何,它必须复制内容。
参数
what_arg
可抛std::bad_alloc...