zoukankan      html  css  js  c++  java
  • C++回顾day03---<异常>

    一:传统错误处理机制(C中通过函数返回来处理)

    int CalcRes(int n, int m, char ch, int& res)
    {
        int err = 0;
        switch (ch)
        {
        case '+':
            res = n + m;
            break;
        case '-':
            res = n - m;
            break;
        case '/':
            if (m == 0)
                err = -1;
            res = 0;
            break;
        case '*':
            res = n*m;
            break;
        }
    
        return err;
    }
    
    void main()
    {
        int res,err;
        err = CalcRes(5, 0, '/', res);
        if (err == -1)
            cout << "calculate error:divide 0" << endl;
        system("pause");
    }

    二:异常处理基本思想

    (一)C++异常处理机制使得异常的引发和处理不必过度关注。上层调用者只需要在适当的位置设置对不同类型异常的处理

    传统的错误处理,通过返回值判断出错,进行处理,或者一步步向上返回错误码,十分复杂。而异常处理机制只需要在适当位置进行出错捕获可以进行错误处理

    (二)异常是专门针对抽象编程中的一系列错误处理的,C++不需要借助函数机制(向C传统错误处理,逐函数返回,无法进行跳跃)

    (三)异常超脱于函数机制(函数之间调用需要压栈出栈操作),遇到异常抛出,可以跨越式回跳,而不需要逐级出栈处理。

    (四)C++异常跨越式回跳:代码实现

    int CalcRes(int n, int m, char ch, int& res)
    {
        int err = 0;
        switch (ch)
        {
        case '+':
            res = n + m;
            break;
        case '-':
            res = n - m;
            break;
        case '/':
            if (m == 0)
                throw n;    //抛出int异常
            res = 0;
            break;
        case '*':
            res = n*m;
            break;
        }
    
        return err;
    }
    
    void t3()
    {
        int res;
        CalcRes(5, 0, '/', res);  //若是异常抛出后会跨越式会跳--->那么后面的红色代码不会显示,因为不会按出栈方式继续执行
        cout << "t3" << endl;
    }
    
    void t2()
    {
        t3();
        cout << "t2" << endl;
    }
    
    void t1()
    {
        t2();
        cout << "t1" << endl;
    }
    
    void main()
    {
        try
        {
            t1();
        }
        catch (int n)
        {
            cout << n << endl;
        }
        system("pause");
    }

    三:C++异常处理的实现

    (一)抛出异常: throw  表达式;

    void func()
    {
        ...
        throw 表达式;
        ...
    }

    (二)捕获并处理异常:try...catch...

    try
    {
        捕获代码块
        例如:调用func()
    }
    catch(异常类型声明)
    {
        异常处理语句
    }
    catch(类型  (形参))
    {
        ...
    }
    ...

    (三)异常处理步骤

    1.若有异常:可以通过throw操作创建一个异常对象并抛出

    2.将可能有异常的代码段嵌入try块进行捕获。

    3.若是没有抛出异常,则跳过catch语句继续向下执行

    4.若是捕获到异常抛出,则执行相关catch语句处理异常,或者若是玉带处理不了的异常可以继续throw向上抛出。

    5.若是到最后,匹配的处理器都未找到,则会调用系统函数terminate(调用abort终止程序)

    (四)案例一:正常捕获异常

    int divide(int x, int y)
    {
        if (y == 0)
            throw x;    //抛出int整型异常
        return x / y;
    }
    
    void main()
    {
        try
        {
            cout << "8/2=" << divide(8, 2) << endl;
            cout << "5/0=" << divide(5, 0) << endl;
        }
        catch (int e)    //捕获int整型异常
        {
            cout << e << " is divide by zero" << endl;
        }
        catch (...)    //...是捕获所有异常
        {
            cout << "catch all exception" << endl;
        }
        system("pause");
    }

    (五)案例二:异常未捕获,触发系统调用abort终止

    class A
    {
    
    };
    
    int divide(int x, int y)
    {
        if (y == 0)
            throw A();    //抛出A类异常
        return x / y;
    }
    
    void main()
    {
        try
        {
            cout << "8/2=" << divide(8, 2) << endl;
            cout << "5/0=" << divide(5, 0) << endl;
        }
        catch (int e)    //捕获int整型异常
        {
            cout << e << " is divide by zero" << endl;
        }
        //catch(A)    //未捕获
        system("pause");
    }

    (六)修改系统默认行为set_terminate--->可以用catch(...)捕获全部,来代替

    #include <exception>

    class
    A { }; int divide(int x, int y) { if (y == 0) throw A(); //抛出A类异常 return x / y; } void my_Terminate() { cout << "exec myself terminate" << endl; exit(-1); } void main() { set_terminate(my_Terminate); //修改系统默认行为(会在系统调用abort之前执行,若是这里异常还没有被处理,那么还是会调用abort) try { cout << "8/2=" << divide(8, 2) << endl; cout << "5/0=" << divide(5, 0) << endl; } catch (int e) //捕获int整型异常 { cout << e << " is divide by zero" << endl; } //catch(A) //未捕获 system("pause"); }
    在vs下未实现,vc++似乎可以实现代码。所以我们一般不要使用它

    (七)捕获严格按照抛出类型匹配

    例如:
    throw int;
    catch(char);是无法捕获的

    四:栈解旋

    在异常被抛出后,即throw异常,之后会对栈上的所有对象进行自动析构。析构顺序与构造相反,这一过程叫做栈的解旋
    class A
    {
    public:
        A()
        {
            cout << "A construct" << endl;
        }
    
        ~A()
        {
            cout << "A distruct" << endl;
        }
    };
    
    class B
    {
    public:
        B()
        {
            cout << "B costruct" << endl;
        }
    
        ~B()
        {
            cout << "B distruct" << endl;
        }
    };
    
    void divide(int n, int m)
    {
        B b;    //对象二后入栈
        if (m == 0)
            throw n;
    }
    
    void t1()
    {
        A a;    //对象一先入栈
        divide(5, 0);
    }
    
    
    void main()
    {
        try
        {
            t1();
        }
        catch (int e)
        {
            cout << e << " divide zeor is err" << endl;
        }
    
        system("pause");
    }

    五:异常接口声明

    (一)为了增强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型(也只能抛出这几个类型)

    void func() throw(A,B,C,D);    //这个函数只能抛出这几个类型

    (二)若是函数声明中没有包含任何异常接口声明,那么这个函数可以抛出任何类型的异常

    (三)一个不允许抛出任何异常的函数

    void func() throw();

    (四)若是一个函数抛出了他的异常接口所不允许的异常,unexpected函数会被调用,该函数默认行为会调用terminate函数终止程序

     六:异常类型和异常变量的生命周期

    (一)throw的异常是有类型的,可以是数字,字符串,类对象,字符...。

    void t1(int flag)    throw(int,char,double,char*,A)    //进行异常接口声明
    {
        if (flag == 0)
            throw 1;    //抛出整型
        else if (flag == 1)
            throw "string throw";    //抛出字符串
        else if (flag == 2)
            throw 'c';    //抛出字符
        else if(flag == 3)
         throw 1.1;
        else
            throw A();    //抛出类对象
    }
    
    
    void main()
    {
        try
        {
            //t1(0);
            //t1(1);
            //t1(2);
            t1(3);
        }
        catch (int e)
        {
            cout << e << endl;
        }
        catch (char c)
        {
            cout << c << endl;
        }
        catch (char* s)
        {
            cout << s << endl;
        }
      catch(double b)
      {
            cout<<b<<endl;
        }
    
        catch (A a)
        {
            cout << "catch obj a" << endl;
        }
    }

    (二)异常变量的生命周期(异常变量周期会在throw之后被释放,catch获取的是一个新的拷贝变量)

    七:标准异常类

    基类Exception中提供了一个what函数,用于返回错误信息,返回类型const char*
    函数声明类型:
    virtual const char* what() const throw();

    (一)标准异常类的继承关系

    其中runtime_error是运行时异常,难以检测。
    logic_error是逻辑错误,可能IDE都会检测出来,易发现
    logic_error和runtime_error两个类及其派生类都有一个接受const string&形参的构造函数---->说明我们可以自己写错误提示信息

    (二)异常类所在的头文件和含义

    (三)标准异常类的使用(模拟一个)

    class A
    {
    public:
        A(int a)
        {
            if (a > 100)
                throw out_of_range("age to long");
        }
    
        ~A()
        {
            cout << "A distruct" << endl;
        }
    };
    
    
    void main()
    {
        try
        {
            A a(101);
        }
        catch (out_of_range e)
        {
            cout << e.what();
        }
    system(
    "pause"); }

    (四)注意:使用exception &e只能捕获其基类为Exception及其子类的所有异常。所以要捕获所有异常可以使用catch(...)更好(但是没有what方法,可以自己定义)

  • 相关阅读:
    终端提示符路径长度设置
    linux ssh服务器
    kail-linux my need
    elasticsearch的marvel
    VPS折腾
    Ubuntu 系统密码相关问题
    Pycharm 使用配置
    python集成开发工具
    Codeforces Round #554 (Div. 2) 选做
    Codeforces Forethought Future Cup Elimination Round 选做
  • 原文地址:https://www.cnblogs.com/ssyfj/p/10778876.html
Copyright © 2011-2022 走看看