从事实时计算多年,熟悉jstorm/spark/flink/kafka/rocketMq, 热衷于开源,希望在这里和前辈们一起学习与分享,得到长足的进步!邮箱:hustfxj@gmail.com 我的githup地址是:https://github.com/hustfxj。欢迎和大家一起交流探讨问题。
分类: C/C++
2013-09-14 13:43:50
C++语言本身或标准程序库所抛出的所有异常,都派生自基类exception。这是其他数个标准异常类别的基类,它们共同构成一个类体系:
图一 标准异常阶层体系
这些标准异常类别分为三组:
(1)语言本身所支持的异常
此类异常用以支撑某些语言特性。主要包括:
bad_alloc:new操作失败会抛出。
bad_cast:执行期间加在一个引用上面的动态性型别转换操作失败时抛出。
bad_typeid:执行RTTI时,交给typeid的参数为零或空指针时抛出
bad_exception:非预期的异常
(2)C++标准程序库发出的异常
总是派生自logic_error。逻辑错误是由于程序内部逻辑而导致的错误。逻辑错误是可以避免的,且在程序开始执行之前,能够被检测到。
C++标准库中定义的逻辑错误如下:
[cpp] view plaincopyprint?
1. class logic_error : public exception {
2. public:
3. explicit logic_error (const string& what_arg);
4. };
5.
6. class invalid_argument : public logic_error {
7. public:
8. explicit invalid_argument (const string& what_arg);
9. };
10.
11. class out_of_range : public logic_error {
12. public:
13. explicit out_of_range (const string& what_arg);
14. };
15.
16. class length_error : public logic_error {
17. public:
18. explicit length_error (const string& what_arg);
19. };
20.
21. class domain_error : public logic_error {
22. public:
23. explicit domain_error (const string& what_arg);
24. }; 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++标准库中的定义如下:
[cpp] view plaincopyprint?
1. class runtime_error : public exception {
2. public:
3. explicit runtime_error (const string& what_arg);
4. };
5.
6. class range_error : public runtime_error {
7. public:
8. explicit range_error (const string& what_arg);
9. };
10.
11. class overflow_error : public runtime_error {
12. public:
13. explicit overflow_error (const string& what_arg);
14. };
15.
16. class underflow_error : public runtime_error {
17. public:
18. explicit underflow_error (const string& what_arg);
19. }; 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:算数运算时发生下溢
实例代码:
[cpp] view plaincopyprint?
1. #include
2. #include
3. #include
4. #include
5. #include
6. #include
7.
8. using namespace std;
9.
10. //自定义配置器,vector分配空间使用
11. template
12. class stingyallocator : public allocator<_Ty>
13. {
14. public:
15. template
16. struct rebind {
17. typedef stingyallocator other;
18. };
19.
20. size_t max_size( ) const
21. {
22. return 10;
23. };
24. };
25.
26. int main()
27. {
28. //逻辑错误:out_of_range
29. try {
30. string str( "Micro" );
31. string rstr( "soft" );
32. str.append( rstr, 5, 3 );
33. cout << str << endl;
34. }
35. catch ( exception &e ) {
36. cerr << "Caught: " << e.what( ) << endl;
37. cerr << "Type: " << typeid( e ).name( ) << endl << endl;
38. };
39.
40. //逻辑错误:length_error
41. try
42. {
43. vector<int, stingyallocator< int > > myv;
44. for ( int i = 0; i < 11; i++ )
45. myv.push_back( i );
46. }
47. catch ( exception &e )
48. {
49. cerr << "Caught " << e.what( ) << endl;
50. cerr << "Type " << typeid( e ).name( ) << endl << endl;
51. };
52.
53. //逻辑错误:invalid_argument
54. try
55. {
56. bitset< 32 > bitset( string( "11001010101100001b100101010110000") );
57. }
58. catch ( exception &e )
59. {
60. cerr << "Caught " << e.what( ) << endl;
61. cerr << "Type " << typeid( e ).name( ) << endl << endl;
62. };
63.
64. //逻辑错误:domain_error
65. try
66. {
67. throw domain_error( "Your domain is in error!" );
68. }
69. catch (exception &e)
70. {
71. cerr << "Caught: " << e.what( ) << endl;
72. cerr << "Type: " << typeid(e).name( ) << endl << endl;
73. };
74.
75. //运行时错误:range_error
76. try
77. {
78. throw range_error( "The range is in error!" );
79. }
80. catch (exception &e)
81. {
82. cerr << "Caught: " << e.what( ) << endl;
83. cerr << "Type: " << typeid( e ).name( ) << endl << endl << endl;
84. };
85.
86. //运行时错误:underflow_error
87. try
88. {
89. throw underflow_error( "The number's a bit small, captain!" );
90. }
91. catch ( exception &e ) {
92. cerr << "Caught: " << e.what( ) << endl;
93. cerr << "Type: " << typeid( e ).name( ) << endl << endl;
94. };
95.
96. //运行时错误:overflow_error
97. try
98. {
99. bitset< 33 > bitset;
100. bitset[32] = 1;
101. bitset[0] = 1;
102. unsigned long x = bitset.to_ulong( );
103. }
104. catch(exception &e)
105. {
106. cerr << "Caught " << e.what() << endl;
107. cerr << "Type: " << typeid(e).name() << endl << endl;
108. }
109.
110. return 0;
111. }
#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;
}
运行结果(CodeBlocks):
参考资料:
常见的异常处理问题
动态内存分配错误
① 分配动态内存使用的是new和new[]操作符,如果他们分配内存失败,就会抛出bad_alloc异常,在new头文件中,所以我们的代码中应该捕捉这些异常。常见的代码形式如下:
[cpp] view plaincopyprint?
1. try {
2. //其他代码
3. ptr = new int[num_max];
4. //其他代码
5. } catch(bad_alloc &e) {
6. //这里常见的处理方式为:先释放已经分配的内存,然后结束程序,或者打印一条错误信息并继续执行
7. }
try {
//其他代码
ptr = new int[num_max];
//其他代码
} catch(bad_alloc &e) {
//这里常见的处理方式为:先释放已经分配的内存,然后结束程序,或者打印一条错误信息并继续执行
}
② 可以使用类似C语言的方式处理,但这时要使用的nothrow版本,使用"new (nothrow)"的形式分配内存。这时,如果分配不成功,返回的是NULL指针,而不再是抛出bad_alloc异常。
③ 可以定制内存分配失败行为。C++允许指定一个new 处理程序(newhandler)回调函数。默认的并没有new 处理程序,如果我们设置了new 处理程序,那么当new和new[] 分配内存失败时,会调用我们设定的new 处理程序,而不是直接抛出异常。通过set_new_handler函数来设置该回调函数。要求被回调的函数没有返回值,也没有形式参数。
注意事项:(以前学java的尤其要注意,和java中不太一样)
① 如果函数没有显式的声明 抛出列表,表示异常可以抛出任意列表。(在java中,如果没有异常抛出列表,那么是不能抛出任何异常的)。
② C++的 “throw()”相当于java的不声明抛出列表。都表示不抛出任何异常。
③ 在C++中,编译的时候,编译器不会对异常抛出列表进行检查。也就是说,如果你声明了抛出列表,即使你的函数代码中抛出了没有在抛出列表中指定的异常,你的程序依然可以通过编译,到运行时才会出错,对于这样的异常,在C++中称为“意外异常”(unexpeced exception)。(这点和java又不相同,在java中,是要进行严格的检查的)。