C++&Qt的异常处理

引言

我们寄希望使用异常这种方法,让一个函数发现自己无法处理的错误时抛出异常或者做进一步处理。未使用异常处理机制的程序,当遇见无法处理的问题时可能会产生如下后果:


程序自行终止(然后程序员开始漫长的找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


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864