目录
2、c++中的异常处理方式(try ... catch ...)
5、try..catch 另类写法 和 函数异常声明/定义 throw()
1、 异常 与 Bug 的区别
“异常”是我们在程序开发中必须考虑的一些特殊情况,是程序运行时就可预料的执行分支(注:异常是不可避免的,如程序运行时产生除 0 的情况;打开的外部文件不存在;数组访问的越界等等);
“Bug”是程序的缺陷,是程序运行时不被预期的运行方式(注:Bug是人为的、可避免的;如使用野指针;堆数组使用结束后未释放等等);
无论是“异常”还是“Bug”,都是程序正常运行过程中可能出现的意外情况。区别是“异常”可以捕获,并做出合适的处理,“Bug"所带来的后果是无法预测的,需要重写相应的代码。
2、c++中的异常处理方式(try ... catch ...)
(1)基本语法
1 // 异常基本语法
2 try
3 {
4 // 可能产生异常的代码,若发生异常,通过 throw 关键字抛出异常
5 }
6 catch(异常类型) // 异常捕获,注(...)代表捕获所有异常
7 {
8 // 处理异常的代码,该异常由try语句块产生
9 }
(2)基本规则
1)同一个 try 语句可以跟上多个 catch 语句(在工程中,将可能产生异常的代码放在 try 语句块中,然后后面跟上多个 catch 语句);
2)try 语句中通过 throw 关键字 可以抛出任何类型的异常(int、字符串、对象等等);
3)catch 语句可以定义具体处理的异常类型,如 catch( int ) 只捕获 int 类型异常, 但无法进一步获取异常信息;catch( int a ) 只捕获 int 类型异常,可以进一步获取异常信息;
4)不同类型的异常由不同的 catch 语句负责处理;
5)catch(...) 用于处理所有类型的异常(只能放在所有 catch语句 的后面);
6)任何异常都只能被捕获(catch)一次;
7)只要被 catch 捕获一次,其它的 catch 就没有捕获机会了;
8)throw 抛出异常的类型 与 catch 捕获异常的类型 必须严格匹配(不能进行类型转换);若匹配成功,则能够捕获该异常;否则捕获失败,程序停止执行。
其实,为了更好的理解 异常抛出 和 异常捕获 这两个动作,我们可以将其想象成 函数调用,抛出异常好比是函数中实参,捕获异常好比是函数中形参,只有当实参的类型 与 形参的类型严格匹配时,这次捕获才能成功。为什么说想象成函数调用,而不是正真的函数调用呢?原因就是:函数调用时,用实参初始化形参时可以进行隐式的类型转换;但是在异常捕获时,必须严格匹配异常类型。
(3)异常抛出(throw exception)的逻辑分析
情况1:异常代码没有放到 try{ } 语句中,这也意味着没有对应的 catch 语句,其实就是普通函数调用,若此时抛出异常(throw),则程序停止执行;
情况2:异常代码放到 try{ throw exception... } 语句中,这也意味着有对应的 catch 语句,则抛出异常时就会与 catch语句严格匹配;若匹配成功,则可以捕获该异常,否则不能捕获该异常,程序停止执行。
throw 抛出异常后,在发生异常的函数中至上而下的严格匹配每一个 catch 语句捕获的异常类型,来判断是否能够捕获该异常;
1) 若发生异常的函数中 能够捕获该异常,则程序接着往下执行;
2) 若发生异常的函数中 不能捕获该异常,则未被处理的异常会顺着函数调用栈向上传播,直到该异常被捕获为止,否则程序将停止执行;
总结:throw 抛出的异常必须被 对应的 catch 捕获,否则程序将停止执行;
通过上图来说明异常抛出后的执行顺序:
1)在 函数 function3 中 抛出异常 throw 1;但是在 function3 中并不能捕获该异常,则异常继续向外层函数 function2 抛出
2)在 函数 function2 中,异常依旧没有被捕获,则异常继续向外层函数 function1 抛出;
3)在 函数 function1 中,异常被 catch 捕获和处理,然后程序继续向下执行;
注:若在 函数 function1 中,异常还是没有被捕获,则异常会一直向外层函数抛出,直到该异常被捕获为止,否在程序停止执行。
代码展示:
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 double divide(double a, double b)
7 {
8 const double delta = 0.000000001;
9 double ret = 0;
10
11 if( !((-delta < b) && (b < delta)) )
12 {
13 ret = a / b;
14 }
15 else
16 {
17 throw "Divided by zero...";
18 }
19
20 cout << "divide(double a, double b)" << endl;
21
22 return ret;
23 }
24
25 double ExceptionFunc()
26 {
27 double d = divide(2, 0);
28
29 cout << "ExceptionFunc()" << endl;
30
31 return d;
32 }
33
34 int main(int argc, char *argv[])
35 {
36 double d = ExceptionFunc();
37
38 cout << "result = " << d << endl;
39
40 return 0;
41 }
42
43 /**
44 * 运行结果:
45 * terminate called after throwing an instance of 'char const*'
46 * Aborted (core dumped)
47 */
48
49 /**
50 * 分析:
51 * throw "Divided by zero..."; 抛出异常后,divide(double a, double b) 函数不能捕获该异常,则异常继续抛给 ExceptionFunc();
52 * 在 ExceptionFunc() 中,也不能捕获该异常,则异常继续抛给 main();
53 * 在 main()中,也不能捕获该异常,则程序停止执行。
54 */
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 double divide(double a, double b)
7 {
8 const double delta = 0.000000001;
9 double ret = 0;
10
11 try
12 {
13 if( !((-delta < b) && (b < delta)) )
14 {
15 ret = a / b;
16 }
17 else
18 {
19 throw "Divided by zero...";
20 }
21 }
22 catch(char const* s)
23 {
24 cout << s << endl;
25 }
26
27 cout << "divide(double a, double b)" << endl;
28
29 return ret;
30 }
31
32 double ExceptionFunc()
33 {
34 double d = divide(2, 0);
35
36 cout << "ExceptionFunc()" << endl;
37
38 return d;
39 }
40
41 int main(int argc, char *argv[])
42 {
43 ExceptionFunc();
44
45 cout << "test end!" << endl;
46
47 return 0;
48 }
49
50 /**
51 * 运行结果:
52 * Divided by zero...
53 * divide(double a, double b)
54 * ExceptionFunc()
55 * test end!
56 */
57
58 /**
59 * 分析:
60 * throw "Divided by zero..."; 抛出异常后,在divide(double a, double b) 中,异常被捕获,则程序继续向下执行;
61 * catch(char const* s) // throw "Divided by zero..."
62 * {
63 * cout << s << endl;
64 * }
65 * cout << "divide(double a, double b)" << endl;
66 *
67 * divide(2, 0); 函数调用结束,返回到 ExceptionFunc() 中,
68 * cout << "ExceptionFunc()" << endl;
69 *
70 * ExceptionFunc()调用结束,返回 main()中,继续向下执行;
71 * cout << "test end!" << endl;
72 */
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 double divide(double a, double b)
7 {
8 const double delta = 0.000000001;
9 double ret = 0;
10
11 if( !((-delta < b) && (b < delta)) )
12 {
13 ret = a / b;
14 }
15 else
16 {
17 throw "Divided by zero...";
18 }
19
20 cout << "divide(double a, double b)" << endl;
21
22 return ret;
23 }
24
25 double ExceptionFunc()
26 {
27 double d;
28
29 try
30 {
31 d = divide(2, 0);
32
33 cout << "d = " << d << endl;
34 }
35 catch(char const* s)
36 {
37 cout << s << endl;
38 }
39
40 cout << "ExceptionFunc()" << endl;
41
42 return d;
43 }
44
45 int main(int argc, char *argv[])
46 {
47 ExceptionFunc();
48
49 cout << "test end!" << endl;
50
51 return 0;
52 }
53
54 /**
55 * 运行结果:
56 * Divided by zero...
57 * ExceptionFunc()
58 * test end!
59 */
60
61 /**
62 * 分析:
63 * throw "Divided by zero..."; 抛出异常后,divide(double a, double b) 函数不能捕获该异常,则异常继续抛给 ExceptionFunc();
64 * 在 ExceptionFunc() 中,异常被捕获,则程序继续向下执行;
65 * catch(char const* s) // throw "Divided by zero..."
66 * {
67 * cout << s << endl;
68 * }
69 * cout << "ExceptionFunc()" << endl;
70 * ExceptionFunc()调用结束,返回 main()中,继续向下执行;
71 * cout << "test end!" << endl;
72 */
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 double divide(double a, double b)
7 {
8 const double delta = 0.000000001;
9 double ret = 0;
10
11 if( !((-delta < b) && (b < delta)) )
12 {
13 ret = a / b;
14 }
15 else
16 {
17 throw "Divided by zero...";
18 }
19
20 cout << "divide(double a, double b)" << endl;
21
22 return ret;
23 }
24
25 double ExceptionFunc()
26 {
27 double d = divide(2, 0);
28
29 cout << "ExceptionFunc()" << endl;
30
31 return d;
32 }
33
34 int main(int argc, char *argv[])
35 {
36 try
37 {
38 double d = ExceptionFunc();
39
40 cout << "d = " << d << endl;
41 }
42 catch(char const* s)
43 {
44 cout << s << endl;
45 }
46
47 cout << "test end!" << endl;
48
49 return 0;
50 }
51
52 /**
53 * 运行结果:
54 * Divided by zero...
55 * test end!
56 */
57
58 /**
59 * 分析:
60 * throw "Divided by zero..."; 抛出异常后,divide(double a, double b) 函数不能捕获该异常,则异常继续抛给 ExceptionFunc();
61 * 在 ExceptionFunc() 中,也不能捕获该异常,则异常继续抛给 main();
62 * 在 main()中,异常与被捕获,则程序继续向下执行
63 * catch(char const* s) // throw "Divided by zero..."
64 * {
65 * cout << s << endl;
66 * }
67 * cout << "test end!" << endl;
68 */
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 void Demo1()
7 {
8 try
9 {
10 throw 2.0;
11 }
12 catch(char c)
13 {
14 cout << "catch(char c)" << endl;
15 }
16 catch(short c)
17 {
18 cout << "catch(short c)" << endl;
19 }
20 catch(double c) // throw 2.0;
21 {
22 cout << "catch(double c)" << endl;
23 }
24 catch(...) // 表示捕获任意类型的异常
25 {
26 cout << "catch(...)" << endl;
27 }
28 }
29
30 void Demo2()
31 {
32 throw string("D.T.Software");
33 }
34
35 int main(int argc, char *argv[])
36 {
37 Demo1();
38
39 try
40 {
41 Demo2();
42 }
43 catch(char* s)
44 {
45 cout << "catch(char *s)" << endl;
46 }
47 catch(const char* cs)
48 {
49 cout << "catch(const char *cs)" << endl;
50 }
51 catch(string ss) // throw string("D.T.Software");
52 {
53 cout << "catch(string ss)" << endl;
54 }
55
56 return 0;
57 }
58 /**
59 * 运行结果:
60 * catch(double c)
61 * catch(string ss)
62 */
63
64 // 结论:异常类型严格匹配,(...)表示捕获任意类型的异常
总结:
情况1:只抛出异常,没有对应地异常捕获;( 没有 try ... catch ... 结构 )
情况2:在try语句块中抛出异常(直接在try语句块中使用 throw 抛出异常;或者try语句块中放入有异常的函数,间接地在函数中使用 throw 抛出异常),然后通过catch语句捕获同类型的异常并进行异常处理;( 现象: 一个 try ... catch ... 结构 )
那么现在我们考虑能不能在情况2的基础上,将捕获到异常继续抛出呢?(在 catch 语句块中重新抛出异常?)
可以在 catch 语句中重新抛出异常,此时需要外层的 try ... catch ...捕获这个异常;
注:catch 语句中只抛出异常,什么也不做;当捕获任意类型的异常时,直接使用 throw 就行。
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 void Demo()
7 {
8 try
9 {
10 throw 'c';
11 }
12 catch(int i)
13 {
14 cout << "Inner: catch(int i)" << endl;
15 throw i;
16 }
17 catch(...)
18 {
19 cout << "Inner: catch(...)" << endl;
20 throw;
21 }
22 }
23
24 int main(int argc, char *argv[])
25 {
26 Demo();
27
28 return 0;
29 }
30
31 /**
32 * 运行结果:
33 * Inner: catch(...)
34 * terminate called after throwing an instance of 'char'
35 * Aborted (core dumped)
36 */
37 // 错误原因:异常重解释之后,没有被捕获
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 void Demo()
7 {
8 try
9 {
10 try
11 {
12 throw 'c';
13 }
14 catch(int i)
15 {
16 cout << "Inner: catch(int i)" << endl;
17 throw i;
18 }
19 catch(...)
20 {
21 cout << "Inner: catch(...)" << endl;
22 throw;
23 }
24 }
25 catch(...)
26 {
27 cout << "Outer: catch(...)" << endl;
28 }
29 }
30
31 int main(int argc, char *argv[])
32 {
33 Demo();
34
35 return 0;
36 }
37 /**
38 * 运行结果:
39 * Inner: catch(...)
40 * Outer: catch(...)
41 */
为什么要在 catch 语句块中重新抛出异常?
在工程中,利用在 catch 语句块中重新解释异常并抛出这一特性,可以统一异常类型。(很晦涩,看下面解释....)
我们通过上图来详细说明这个情况:
背景介绍:出于开发效率考虑,在工程开发中一般会基于第三方库来开发,但是,第三方库中的某些功能并不完善(可读性差),此时就需要封装第三方库中的这个功能。
在上图中,由于第三方库中 func()函数的异常类型是 int 类型,可读性很差,不能够直接通过异常结果知道该异常所代表的意思;基于这种情况,我们通过私有库中的 MyFunc()函数对第三方库中func()进行了封装,使得 MyFunc()函数中的异常类型可以显示更多的异常信息(MyFunc() 函数中的异常类型是自定义类型,可以是字符串、类类型等等),增强代码的可读性;为了将 func()中的异常类型 和 MyFunc() 中异常类型统一起来,我们可以在私有库中的MyFunc() 函数中去捕获第三方库中的 func() 函数抛出的异常,然后根据捕获到的异常重新解释为我们想要的异常,这样我们工程开发中所面对的异常类型就是一致的;接下来我们用代码复现这个场景:
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 /*
7 假设:当前的函数是第三方库中的函数,因此,我们无法修改源代码
8
9 函数名: void func(int i)
10 抛出异常的类型: int
11 -1 ==》 参数异常
12 -2 ==》 运行异常
13 -3 ==》 超时异常
14 */
15 void func(int i)
16 {
17 if( i < 0 )
18 {
19 throw -1;
20 }
21
22 if( i > 100 )
23 {
24 throw -2;
25 }
26
27 if( i == 11 )
28 {
29 throw -3;
30 }
31
32 cout << "Run func..." << endl;
33 }
34
35 int main(int argc, char *argv[])
36 {
37 try
38 {
39 func(11);
40 }
41 catch(int i)
42 {
43 cout << "Exception Info: " << i << endl;
44 }
45
46 return 0;
47 }
48
49 /**
50 * 运行结果:
51 * Exception Info: -3
52 */
53
54 // 异常显示结果太简单,当发生异常时,需要查询技术文档才能知道这儿的-3代表的意思,可读性很差
// 异常的重解释,在 catch 语句中重新抛出异常
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 /*
7 假设: 当前的函数式第三方库中的函数,因此,我们无法修改源代码
8
9 函数名: void func(int i)
10 抛出异常的类型: int
11 -1 ==》 参数异常
12 -2 ==》 运行异常
13 -3 ==》 超时异常
14 */
15 void func(int i)
16 {
17 if( i < 0 )
18 {
19 throw -1;
20 }
21
22 if( i > 100 )
23 {
24 throw -2;
25 }
26
27 if( i == 11 )
28 {
29 throw -3;
30 }
31
32 cout << "Run func..." << endl;
33 }
34
35 /* 不能修改 func() 函数,则我们定义 MyFunc() 函数重解释 func() 的异常 */
36 void MyFunc(int i)
37 {
38 try
39 {
40 func(i);
41 }
42 catch(int i)
43 {
44 switch(i)
45 {
46 case -1:
47 throw "Invalid Parameter"; // 可以抛出更详细的数据,如类对象,后续讲解
48 break;
49 case -2:
50 throw "Runtime Exception";
51 break;
52 case -3:
53 throw "Timeout Exception";
54 break;
55 }
56 }
57 }
58
59 int main(int argc, char *argv[])
60 {
61 try
62 {
63 MyFunc(11);
64 }
65 catch(const char* cs)
66 {
67 cout << "Exception Info: " << cs << endl;
68 }
69
70 return 0;
71 }
72 /**
73 * 运行结果:
74 * Exception Info: Timeout Exception
75 */
3、自定义异常类的使用方式
(1)异常的类型可以是自定义类类型;
(2)对于类类型异常的匹配依旧是自上而下严格匹配;
(3)赋值兼容性原则在异常匹配中依然适用;(注:在赋值兼容性中,子类是特殊的父类,父类可以捕获子类的异常;同样满足异常类型严格匹配的原则)
(4)在赋值兼容性原则中,一般将
1)匹配子类异常的 catch 放在上部;
2)匹配父类异常的 catch 放在下部;
(5)在定义 catch 语句块时,推荐使用 const 引用作为参数,提高程序的运行效率;
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 class Base
7 {
8 };
9
10 /* 定义异常类 */
11 class Exception : public Base
12 {
13 int m_id;
14 string m_desc;
15 public:
16 Exception(int id, string desc)
17 {
18 m_id = id;
19 m_desc = desc;
20 }
21
22 int id() const
23 {
24 return m_id;
25 }
26
27 string description() const
28 {
29 return m_desc;
30 }
31 };
32
33 /*
34 假设: 当前的函数式第三方库中的函数,因此,我们无法修改源代码
35 函数名: void func(int i)
36 抛出异常的类型: int
37 -1 ==》 参数异常
38 -2 ==》 运行异常
39 -3 ==》 超时异常
40 */
41
42 void func(int i)
43 {
44 if( i < 0 )
45 {
46 throw -1;
47 }
48
49 if( i > 100 )
50 {
51 throw -2;
52 }
53
54 if( i == 11 )
55 {
56 throw -3;
57 }
58
59 cout << "Run func..." << endl;
60 }
61
62 /* 使用自定义的类类型来优化 */
63 void MyFunc(int i)
64 {
65 try
66 {
67 func(i);
68 }
69 catch(int i)
70 {
71 switch(i)
72 {
73 case -1:
74 throw Exception(-1, "Invalid Parameter"); // 直接调用构造函数生成异常对象;
75 break;
76 case -2:
77 throw Exception(-2, "Runtime Exception");
78 break;
79 case -3:
80 throw Exception(-3, "Timeout Exception");
81 break;
82 }
83 }
84 }
85
86 int main(int argc, char *argv[])
87 {
88 try
89 {
90 MyFunc(11);
91 }
92 catch(const Exception& e) // 1 使用 const 引用类型作为参数 2 赋值兼容性原则(参考第4点)
93 {
94 cout << "Exception Info: " << endl;
95 cout << " ID: " << e.id() << endl;
96 cout << " Description: " << e.description() << endl;
97 }
98 catch(const Base& e)
99 {
100 cout << "catch(const Base& e)" << endl;
101 }
102
103 return 0;
104 }
105 /**
106 * 运行结果:
107 * Exception Info:
108 * ID: -3
109 * Description: Timeout Exception
110 */
4、C++ 标准库中的异常类
(1)C++ 标准库中提供了实用异常类族;
(2)标准库中的异常都是从 exception 类派生的;
(3)exception 类有两个主要的分支:
1)logic_error
2)runtime_error
(4)标准库中的异常类继承图:
1 #include <iostream>
2 #include <string>
3 #include <stdexcept>
4 #include <sstream>
5
6 using namespace std;
7
8 /*
9 __FILE__ __FUNCTION__ const char[]
10 __LINE__ int
11 */
12
13 template
14 <typename T, int N>
15 class Array
16 {
17 private:
18 T arr[N];
19 public:
20 Array();
21 T& operator[] (int index);
22 void print() const;
23 };
24
25 template
26 <typename T, int N>
27 Array<T, N>::Array()
28 {
29 for(int i = 0; i < N; i++)
30 {
31 arr[i] = 0;
32 }
33 }
34
35 template
36 <typename T, int N>
37 T& Array<T, N>::operator[] (int index)
38 {
39 if( (0 <= index) && (index < N) )
40 {
41 return arr[index];
42 }
43 else
44 {
45 ostringstream oss;
46
47 throw out_of_range(string(__FILE__) + ":" + static_cast<ostringstream&>(oss << __LINE__).str() + ":" + __FUNCTION__\
48
49 + "\t >> exception: the index of array is out of range");
50 }
51 }
52
53 template
54 <typename T, int N>
55
56 void Array<T, N>::print() const
57 {
58 for(int i = 0; i < N; i++)
59 {
60 cout << arr[i] << " ";
61 }
62 cout << endl;
63 }
64
65 int main(int argc, char *argv[])
66 {
67 try
68 {
69 Array<int, 5> arr;
70
71 arr.print();
72 arr[-1] = 1; // 异常测试
73 arr.print();
74 }
75
76 catch(const out_of_range& e) // 1 使用 const 引用类型作为参数 2 赋值兼容性原则(参考第4点)
77 {
78 cout << e.what() << endl;
79 }
80
81 catch(...)
82 {
83 cout << "other exception ... " << endl;
84 }
85
86 return 0;
87 }
88
89 /**
90 * 运行结果:
91 * 0 0 0 0 0
92 * test.cpp:47:operator[] >> exception: the index of array is out of range
93 */
1 // 模板文件 Array.hpp 的优化
2 #ifndef ARRAY_H
3 #define ARRAY_H
4
5 #include <stdexcept> // 标准库中的异常类头文件;
6
7 using namespace std;A
8
9 template
10 < typename T, int N >
11 class Array
12 {
13 T m_array[N];
14 public:
15 int length() const;
16 bool set(int index, T value);
17 bool get(int index, T& value);
18 T& operator[] (int index);
19 T operator[] (int index) const;
20 virtual ~Array();
21 };
22
23 template
24 < typename T, int N >
25 int Array<T, N>::length() const
26 {
27 return N;
28 }
29
30 template
31 < typename T, int N >
32 bool Array<T, N>::set(int index, T value)
33 {
34 bool ret = (0 <= index) && (index < N);
35
36 if( ret )
37 {
38 m_array[index] = value;
39 }
40
41 return ret;
42 }
43
44 template
45 < typename T, int N >
46 bool Array<T, N>::get(int index, T& value)
47 {
48 bool ret = (0 <= index) && (index < N);
49
50 if( ret )
51 {
52 value = m_array[index];
53 }
54
55 return ret;
56 }
57
58 template
59 < typename T, int N >
60 T& Array<T, N>::operator[] (int index)
61 {
62 if( (0 <= index) && (index < N) )
63 {
64 return m_array[index]; // 这里之前没有验证 index 是否合法,因为验证了也没办法处理;
65 }
66 else
67 {
68 throw out_of_range("T& Array<T, N>::operator[] (int index)");
69 }
70 }
71
72 template
73 < typename T, int N >
74 T Array<T, N>::operator[] (int index) const
75 {
76 if( (0 <= index) && (index < N) )
77 {
78 return m_array[index]; // 这里之前没有验证 index 是否合法,因为验证了也没办法处理;
79 }
80 else
81 {
82 throw out_of_range("T Array<T, N>::operator[] (int index) const");
83 }
84 }
85
86 template
87 < typename T, int N >
88 Array<T, N>::~Array()
89 {
90
91 }
92
93 #endif
94
95 //------------------------------------------------------------------
96
97 // 模板文件 HeapArray.hpp 的优化
98
99 #ifndef HEAPARRAY_H
100 #define HEAPARRAY_H
101
102 #include <stdexcept> // 添加标准头文件;
103
104 using namespace std;
105
106 template
107 < typename T >
108 class HeapArray
109 {
110 private:
111 int m_length;
112 T* m_pointer;
113
114 HeapArray(int len);
115 HeapArray(const HeapArray<T>& obj);
116 bool construct();
117 public:
118 static HeapArray<T>* NewInstance(int length);
119 int length() const;
120 bool get(int index, T& value);
121 bool set(int index ,T value);
122 T& operator [] (int index);
123 T operator [] (int index) const;
124 HeapArray<T>& self();
125 const HeapArray<T>& self() const; // 要考虑成员函数有没有必要成为 const 函数,const 函数主要是给 cosnt 对象调用;
126 ~HeapArray();
127 };
128
129 template
130 < typename T >
131 HeapArray<T>::HeapArray(int len)
132 {
133 m_length = len;
134 }
135
136 template
137 < typename T >
138 bool HeapArray<T>::construct()
139 {
140 m_pointer = new T[m_length];
141
142 return m_pointer != NULL;
143 }
144
145 template
146 < typename T >
147 HeapArray<T>* HeapArray<T>::NewInstance(int length)
148 {
149 HeapArray<T>* ret = new HeapArray<T>(length);
150
151 if( !(ret && ret->construct()) )
152 {
153 delete ret;
154 ret = 0;
155 }
156
157 return ret;
158 }
159
160 template
161 < typename T >
162 int HeapArray<T>::length() const
163 {
164 return m_length;
165 }
166
167 template
168 < typename T >
169 bool HeapArray<T>::get(int index, T& value)
170 {
171 bool ret = (0 <= index) && (index < length());
172
173 if( ret )
174 {
175 value = m_pointer[index];
176 }
177
178 return ret;
179 }
180
181 template
182 < typename T >
183 bool HeapArray<T>::set(int index, T value)
184 {
185 bool ret = (0 <= index) && (index < length());
186
187 if( ret )
188 {
189 m_pointer[index] = value;
190 }
191
192 return ret;
193 }
194
195 template
196 < typename T >
197 T& HeapArray<T>::operator [] (int index)
198 {
199 if( (0 <= index) && (index < length()) )
200 {
201 return m_pointer[index]; // 优化这里,越界抛异常;
202 }
203 else
204 {
205 throw out_of_range("T& HeapArray<T>::operator [] (int index)");
206 }
207 }
208
209 template
210 < typename T >
211 T HeapArray<T>::operator [] (int index) const
212 {
213 if( (0 <= index) && (index < length()) )
214 {
215 return m_pointer[index]; // 优化这里,越界抛异常;
216 }
217 else
218 {
219 throw out_of_range("T HeapArray<T>::operator [] (int index) const");
220 }
221 }
222
223 template
224 < typename T >
225 HeapArray<T>& HeapArray<T>::self()
226 {
227 return *this;
228 }
229
230 template
231 < typename T >
232 const HeapArray<T>& HeapArray<T>::self() const
233 {
234 return *this;
235 }
236
237 template
238 < typename T >
239 HeapArray<T>::~HeapArray()
240 {
241 delete[]m_pointer;
242 }
243
244 #endif
245
246 //------------------------------------------------------------------
247
248 // 测试文件 main.cpp
249
250 #include <iostream>
251 #include <string>
252 #include <memory> //for auto_ptr
253 #include "Array.hpp"
254 #include "HeapArray.hpp"
255
256 using namespace std;
257
258 void TestArray()
259 {
260 Array<int, 5> a;
261
262 for(int i=0; i<a.length(); i++)
263 {
264 a[i] = i;
265 }
266
267 for (int i=0; i<a.length(); i++)
268 {
269 cout << a[i] << ", ";
270 }
271 cout << endl;
272 }
273
274 void TestHeapArray()
275 {
276 //使用智能指针,目的是自动释放堆空间
277 auto_ptr< HeapArray<double> > pa(HeapArray<double>::NewInstance(5));
278
279 if(pa.get() != NULL)
280 {
281 HeapArray<double>& array = pa->self();
282
283 for(int i=0; i<array.length(); i++)
284 {
285 array[i] = i;
286 }
287
288 for (int i=0; i<array.length(); i++)
289 {
290 cout << array[i] << ", ";
291 }
292 cout << endl;
293 }
294 }
295
296 int main(int argc, char *argv[])
297 {
298 try
299 {
300 TestArray();
301
302 cout << endl;
303
304 TestHeapArray();
305 }
306 catch(const out_of_range& e)
307 {
308 cout << "exception: " << e.what() << endl;
309 }
310 catch(...)
311 {
312 cout << "other exception ... " << endl;
313 }
314
315 return 0;
316 }
317
318 /**
319 * 运新结果:
320 * 0, 1, 2, 3, 4,
321 * ---------------------
322 * 0, 1, 2, 3, 4,
323 * Run End...
324 */
325
326 /**
327 * 栈空间数组下标越界异常运行结果:
328 * exception: T& Array<T, N>::operator[] (int index)
329 * Run End...
330 */
331
332 /**
333 * 堆空间数组下标越界异常运行结果:
334 * 0, 1, 2, 3, 4,
335 * ---------------------
336 * exception: T& HeapArray<T>::operator [] (int index)
337 * Run End...
338 */
5、try..catch 另类写法 和 函数异常声明/定义 throw()
try..catch 另类写法(不建议使用)的特点:
(1)try-catch用于分隔正常功能代码与异常处理代码
(2)try-catch可以直接将函数实现分隔为2部分
函数异常声明/定义的特点:
(1)函数声明和定义时可以直接指定可能抛出的异常类型;
(2)异常声明成为函数的一部分,可以提高代码可读性;
(3)函数异常声明是一种与编译器之间的契约;
(4)函数声明异常后就只能抛出声明的异常;
A、抛出其它异常将导致程序运行终止;
B、可以直接通过异常声明定义无异常函数;
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 // int func(int i, int j) throw() // 无异常函数声明
7
8 int func(int i, int j) throw(int, char) //异常声明,表示该函数可能抛出int和char两种类型的异常
9 {
10 if ((0 < j) && (j < 10))
11 {
12 return (i + j);
13 }
14 else
15 {
16 throw 'c'; // 只能抛出指定的异常类型(int、char),否则程序运行失败
17 }
18 }
19
20 //以下的写法已经不被推荐 !!!
21 void test(int i) try //正常代码
22 {
23 cout << "func(i, i) = " << func(i, i) << endl;
24 }
25 catch (int j) //异常代码
26 {
27 cout << "Exception: " << j << endl;
28 }
29 catch (char j) //异常代码
30 {
31 cout << "Exception: " << j << endl;
32 }
33
34 int main(int argc, char *argv[])
35 {
36 test(5); //正常
37
38 test(10); //抛异常
39
40 return 0;
41 }
42 /**
43 * 运行结果:
44 * func(i, i) = 10
45 * Exception: c
46 */
原文出处:https://www.cnblogs.com/nbk-zyc/p/12449331.html