美文网首页
C++异常处理

C++异常处理

作者: 第八区 | 来源:发表于2017-08-24 16:03 被阅读24次

    要点

    • 异常根据抛出的类型捕获,可以直接捕获接收或通过引用接收。但二者同时只能存在一个。
    • 栈内存创建的对象指针抛出后会产生野指针问题
    • 动态创建对象的指针抛出后可以正常捕获使用,但是需要手动释放。
    • 函数声明可以加上异常声明。限制函数可以抛出的异常类型。
    • 异常有栈解锁机制,栈内存中创建的对象在异常抛出后会自动析构。
    • 异常可以捕获并继续向上抛出。

    示例代码

    #include "stdafx.h"
    #include "iostream"
    #include "string.h"
    using namespace std;
    #pragma warning(disable : 4996)  
    class ExceptionA {
    private:
        char *msg;
    public:
        ExceptionA(const char *msg) {
            cout << "构造" <<msg<< endl;
            if (msg == NULL) {
                this->msg = NULL;
            }else{
                this->msg = new char[strlen(msg) + 1];
                strcpy(this->msg, msg);
            }
        }
        char * getMsg()const {
            return this->msg;
        }
        ExceptionA(const ExceptionA& e) {
            cout << "拷贝构造" << endl;
            if (this->msg == NULL) {
                delete[]this->msg;
            }
            this->msg = new char[strlen(e.getMsg()) + 1];
            strcpy(this->msg, e.getMsg());
        }
        ~ExceptionA() {
            cout << "析构" << msg << endl;
            if (this->msg != NULL) {
                delete[]this->msg;
            }
        }
    };
    
    void funcA(int x) {
    
        switch (x)
        {
        case 0:{
            //throw异常后,temp1会自动析构,而temp不会自动析构和释放
            ExceptionA *temp = new ExceptionA("temp");
            ExceptionA temp1("temp1");
            throw 1;
        }
            break;
        case 1:
            throw 'a';
            break;
        case 2:
            //可以直接接受或使用引用接收。推荐使用引用接收
            throw(ExceptionA("msg 2"));
            break;
        case 3:
            //抛出指针,但对象会被清理。catch到的指针是野指针
            throw(&ExceptionA("msg 3"));
            break;
        case 4: {
            //抛出动态分配的指针。catch到后使用完后需要delete
            ExceptionA* e = new ExceptionA("msg4");
            throw(e);
        }
            break;
        case 5:
            throw 3.14f;
        case 6:
            throw 3.14;
        }
        cout << "funcA success " << x << endl;
    }
    
    void funcB(int index) throw(float ,double){
        try {
            funcA(index);
        }
        catch (int e) {
            cout << "catch int " << e << endl;
        }
        catch (char e) {
            cout << "catch char " << e << endl;
        }
        catch (ExceptionA e) {
            cout << "catch  ExceptionA " << e.getMsg() << endl;
        }
        //使用对象接收和使用对象的引用接收不能同时存在。
        //catch (ExceptionA &e) {
        //  cout << "catch  ExceptionA & " << e.getMsg() << endl;
        //}
        catch (ExceptionA *e) {
            cout << "catch  ExceptionA * " << e->getMsg() << endl;
            delete e;
        }
        catch (float e) {
            //接续向上抛出异常
            cout << "catch float and throw  " << e << endl;
            throw e;
        }
        catch (double e) {
            //接续向上抛出异常,但函数的方法上有限制可以抛出异常的类型。这里会出错
            cout << "catch double and throw  " << e << endl;
            throw e;
        }
    }
    int main()
    {
        try {
            funcB(6);
        }
        catch (float e) {
            cout << "main catch " << e << endl;
        }
        return 0;
    }
    

    异常处理场景演示

    • funcB(0)


      0.png

      这里创建了两个对象一个在堆中动态创建temp.一个在栈中temp1。执行结果看到temp1自动被析构,而temp未被析构。c++在异常抛出后有栈解锁机制,会自动析构在栈中创建的对象。

    • funcB(1)


      1.png

      这里就是按类型在funcA中正常的catch

    • funcB(2) 栈内存对象

      • 用对象直接接收


        2.png

        这里看到当抛出对象时候,catch中接受时类似方法实参到形参的传递,进行拷贝构造。

      • 用对象的引用接收


        7.png

        catch中得到对象的引用。

    • funcB(3) 抛出栈内存对象的指针


      3

      catch得到对象的指针前。对象已被析构,这里得到的就是野指针。

    • funcB(4) 动态创建对象


      4.png

      可以正常catch到并使用。但使用完后需要手动释放。

    • funcB(5) 捕获到异常后继续向上抛出


      5.png

      funcA中继续抛出,在main中正常捕获。

    • funcB(6) 方法异常类型声明


      6.png

      限制方法能够抛出异常的类型,如果不在范围内,运行会报错

    相关文章

      网友评论

          本文标题:C++异常处理

          本文链接:https://www.haomeiwen.com/subject/dpjedxtx.html