我们寄希望使用异常这种方法,让一个函数发现自己无法处理的错误时抛出异常或者做进一步处理。未使用异常处理机制的程序,当遇见无法处理的问题时可能会产生如下后果:
第一种情况在软件开发过程中是不明智的,当软件体量的增大,找bug的过程往往将浪费掉大量时间。第二种情况,比较常用,但是有时不合适,例如返回错误码是int,每个调用都要检查错误值,极不方便,也容易让程序规模加倍。第三种情况,很容易误导调用者。
通过使用异常,把错误和相应处理分开。由函数抛出异常,调用者可以根据捕获异常判断程序出错原因和位置,做出相应处理。是否终止程序由调用者掌握,而不是任由程序自行宕机。
假设我们写一个程序,把用户输入的两个字符串转换为整数,相加输出
#include
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
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
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要好,程序出现错误,却继续无声无息执行下去。
防止除数为0
#include
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<"/"<"="<cout<"/"<"="<catch(int)//异常类型
{
cout<<"除数为0,计算错误!"<//异常处理语句
}
catch(double)//异常类型
{
cout<<"除数为0.0,计算错误!"<//异常处理语句
}
return 0;
}
例3
求三角形周长
#include
#include
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<cout<return 0;
}
例4
在异常处理中处理析构函数
#include
#include
using namespace std;
class Student
{
public:
Student(int n,string nam):num(n), name(nam)
{
cout<<"constructor-"<cout<<"destructor-"<void get_data( );
private:
int num;
string name;
};
void Student::get_data( )
{
if(num==0)
throw num; //如num=0,抛出int型变量num
else
cout<" "<cout<" is in get_data()!"<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="<",error!"<return 0;
}
例5
在函数嵌套的情况下检测异常处理
#include
using namespace std;
int main( )
{
void f1( );
try
{
f1( ); //调用f1( )
}
catch(double)
{
cout<<"OK0!"<cout<<"end0"<return 0;
}
void f1( )
{
void f2( );
try
{
f2( ); //调用f2( )
}
catch(char)
{
cout<<"OK1!";
}
cout<<"end1"<void f2( )
{
void f3( );
try
{
f3( ); //调用f3( )
}
catch(int)
{
cout<<"Ok2!"<cout<<"end2"<void f3( )
{
double a=0;
try
{
throw a; //抛出double类型异常信息
}
catch(float)
{
cout<<"OK3!"<cout<<"end3"<
参考
https://www.cnblogs.com/ggjucheng/archive/2011/12/18/2292089.html
http://blog.csdn.net/sxhelijian/article/details/46128213