c/c++语言开发共享c++中的异常处理

异常的基本处理方式、异常的重解释(在 catch 语句块中将捕获到的异常再次抛出)、自定义/标准库异常类的使用(注意:赋值兼容性原则)、异常的另类写法(try…catch…)、异常函数声明的方式(通过 throw 关键字指定可抛出的具体异常类型) …


 目录

  1、 异常 与 bug 的区别

  4、c++ 标准库中的异常类

 

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 捕获异常的类型  必须严格匹配(不能进行类型转换);若匹配成功,则能够捕获该异常;否则捕获失败,程序停止执行。

    c++中的异常处理

  其实,为了更好的理解 异常抛出 和 异常捕获 这两个动作,我们可以将其想象成 函数调用,抛出异常好比是函数中实参,捕获异常好比是函数中形参,只有当实参的类型 与 形参的类型严格匹配时,这次捕获才能成功。为什么说想象成函数调用,而不是正真的函数调用呢?原因就是:函数调用时,用实参初始化形参时可以进行隐式的类型转换;但是在异常捕获时,必须严格匹配异常类型。  

(3)异常抛出(throw exception)的逻辑分析

  情况1:异常代码没有放到  try{ }  语句中,这也意味着没有对应的 catch 语句,其实就是普通函数调用,若此时抛出异常(throw),则程序停止执行;

  情况2:异常代码放到  try{ throw exception… }  语句中,这也意味着有对应的 catch 语句,则抛出异常时就会与 catch语句严格匹配;若匹配成功,则可以捕获该异常,否则不能捕获该异常,程序停止执行。

  throw 抛出异常后,在发生异常的函数中至上而下的严格匹配每一个 catch 语句捕获的异常类型,来判断是否能够捕获该异常;

   1) 若发生异常的函数中  能够捕获该异常,则程序接着往下执行;

   2) 若发生异常的函数中  不能捕获该异常,则未被处理的异常会顺着函数调用栈向上传播,直到该异常被捕获为止,否则程序将停止执行;

  总结:throw 抛出的异常必须被 对应的 catch 捕获,否则程序将停止执行;

    c++中的异常处理

  通过上图来说明异常抛出后的执行顺序:

  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 就行。

  c++中的异常处理

 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 语句块中重新解释异常并抛出这一特性,可以统一异常类型。(很晦涩,看下面解释….)

  c++中的异常处理

  我们通过上图来详细说明这个情况:

  背景介绍:出于开发效率考虑,在工程开发中一般会基于第三方库来开发,但是,第三方库中的某些功能并不完善(可读性差),此时就需要封装第三方库中的这个功能。

  在上图中,由于第三方库中 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)标准库中的异常类继承图:

    c++中的异常处理

 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  */

  

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/600140.html

(0)
上一篇 2021年5月9日
下一篇 2021年5月9日

精彩推荐