引言
我们寄希望使用异常这种方法,让一个函数发现自己无法处理的错误时抛出异常或者做进一步处理。未使用异常处理机制的程序,当遇见无法处理的问题时可能会产生如下后果:
程序自行终止(然后程序员开始漫长的找bug过程)
返回一个表示错误的值(很多系统函数都是这样,例如malloc,内存不足,分配失败,返回NULL指针)
返回一个合法值,让程序处于某种非法的状态(最坑爹的东西,有些第三方库真会这样)
调用一个预先准备好在出现”错误”的情况下用的函数。
第一种情况在软件开发过程中是不明智的,当软件体量的增大,找bug的过程往往将浪费掉大量时间。第二种情况,比较常用,但是有时不合适,例如返回错误码是int,每个调用都要检查错误值,极不方便,也容易让程序规模加倍。第三种情况,很容易误导调用者。
通过使用异常,把错误和相应处理分开。由函数抛出异常,调用者可以根据捕获异常判断程序出错原因和位置,做出相应处理。是否终止程序由调用者掌握,而不是任由程序自行宕机。
异常处理的方法
例1
假设我们写一个程序,把用户输入的两个字符串转换为整数,相加输出
#include <iostream> void main() { char *str1 = "1", *str2 = "2"; int num1 = atoi(str1); int num2 = atoi(str2); std::cout << "sum is "<< num1 + num2 << std::endl; }
假设用户输入的是str1,str2,如果str1和str2都是整数类型的字符串,这段代码是可以正常工作的,但是用户的输入有可能误操作,输入了非法字符,例如
#include <iostream> void main() { char *str1 = "1", *str2 = "a"; int num1 = atoi(str1); int num2 = atoi(str2); std::cout << "sum is "<< num1 + num2 << std::endl; }
这个时候结果是1,因为atoi(str2)返回0。如果用户输入是这样:
#include <iostream> void main() { char *str1 = "1", *str2 = NULL; int num1 = atoi(str1); int num2 = atoi(str2); std::cout << "sum is "<< num1 + num2 << std::endl; }
那么这段代码会出现段错误,程序异常退出。
如果在一个重要系统中,调用者不知情,传入了一个NULL字符,程序就异常退出了,导致服务中断,或者传入非法字符,结果返回0。为了解决这种问题,异常处理改造一个安全的atoi方法,叫parseNumber。
class NumberParseException {}; bool isNumber(char * str) { using namespace std; if (str == NULL) return false; int len = strlen(str); if (len == 0) return false; bool isaNumber = false; char ch; for (int i = 0; i < len; i++) { if (i == 0 && (str[i] == '-' || str[i] == '+')) continue; if (isdigit(str[i])) { isaNumber = true; } else { isaNumber = false; break; } } return isaNumber; } int parseNumber(char * str) throw(NumberParseException) { if (!isNumber(str)) throw NumberParseException(); return atoi(str); } void main() { char *str1 = "1", *str2 = NULL; try { int num1 = parseNumber(str1); int num2 = parseNumber(str2); std::cout << "sum is " << num1 + num2 << std::endl; } catch (NumberParseException) { std::cout << "输入不是整数\n"; } }
上述代码中NumberParseException是自定义的异常类,当检测的时候传入的str不是一个数字时,就抛出一个数字转换异常,让调用者处理错误,这比传入NULL字符串,导致段错误结束程序好得多,调用者可以捕获这个异常,决定是否结束程序,也比传入一个非整数字符串,返回0要好,程序出现错误,却继续无声无息执行下去。
例2
防止除数为0
#include <iostream> using namespace std; template <typename T> T Div(T x,T y) { if(y==0) throw y;//抛出异常 return x/y; } int main() { int x=5,y=0; double x1=5.5,y1=0.0; try { //被检查的语句 cout<<x<<"/"<<y<<"="<<Div(x,y)<<endl; cout<<x1<<"/"<<y1<<"="<<Div(x1,y1)<<endl; } catch(int)//异常类型 { cout<<"除数为0,计算错误!"<<endl;//异常处理语句 } catch(double)//异常类型 { cout<<"除数为0.0,计算错误!"<<endl;//异常处理语句 } return 0; }
例3
求三角形周长
#include <iostream> #include <stdexcept> using namespace std; int triangle(int a, int b, int c) { if(a<0 || b<0 || c<0 || a+b<=c || a+c<=b || b+c<=a) throw runtime_error("The lengths of three sides can't form triangle"); return a + b + c; } int main() { int total = 0; try { total = triangle(3,4,7); } catch(const runtime_error& e) { cout<<e.what()<<endl; } cout<<total<<endl; return 0; }
例4
在异常处理中处理析构函数
#include <iostream> #include <string> using namespace std; class Student { public: Student(int n,string nam):num(n), name(nam) { cout<<"constructor-"<<n<<endl; } ~Student( ) { cout<<"destructor-"<<num<<endl; } void get_data( ); private: int num; string name; }; void Student::get_data( ) { if(num==0) throw num; //如num=0,抛出int型变量num else cout<<num<<" "<<name<<endl; cout<<num<<" is in get_data()!"<<endl; } void fun( ) { Student stud1(1101,"Tan"); stud1.get_data( ); Student stud2(0,"Li"); stud2.get_data( ); } int main( ) { try { fun( ); } catch(int n) { cout<<"num="<<n<<",error!"<<endl; } return 0; }
例5
在函数嵌套的情况下检测异常处理
#include <iostream> using namespace std; int main( ) { void f1( ); try { f1( ); //调用f1( ) } catch(double) { cout<<"OK0!"<<endl; } cout<<"end0"<<endl; return 0; } void f1( ) { void f2( ); try { f2( ); //调用f2( ) } catch(char) { cout<<"OK1!"; } cout<<"end1"<<endl; } void f2( ) { void f3( ); try { f3( ); //调用f3( ) } catch(int) { cout<<"Ok2!"<<endl; } cout<<"end2"<<endl; } void f3( ) { double a=0; try { throw a; //抛出double类型异常信息 } catch(float) { cout<<"OK3!"<<endl; } cout<<"end3"<<endl; }
另可以参考本站内一篇:
《C++异常处理 》
————————————————
版权声明:本文为CSDN博主「吕小猪不坏」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wokaowokaowokao12345/article/details/78567409

