美文网首页C++
C++语法系列之9-- 异常处理

C++语法系列之9-- 异常处理

作者: hello12qwerz | 来源:发表于2018-04-01 23:36 被阅读0次

    1 异常常识:

    1)使用throw抛出异常;
    2)使用try-catch 语句块捕获异常;
    3)catch语句块中,可以使用throw再次抛出当前异常

    try {
       g();
    } catch (int i) {
       throw;//再次抛出异常 
    }
    

    4)可以抛出任意类型的异常。可以是对象,也可以是简单的基础类型。

    void process() { 
       if (fail) {
          throw 5;
       }
    }
    
    try {
      process():
    } catch (int e) {
      return 1;
    }
    

    5)也可以抛出C风格的字符串char*

    void process() {
       if (fail) {
          throw "failed exception"
       }
    }
    
    try {
      process():
    } catch (const char* e) {
       std:cerr << e << endl;
    }
    

    6)通常应该抛出对象。因为对象的类名称可以传递信息;此外异常可以存储信息,包括用于描述异常的字符串;
    7) 以下为匹配所有异常的代码:

    try {
    
    } catch (...) {
    
    }
    
    try {
    
    }  catch (const invalid_argument& e) {
    
    } catch (const runtime_error& e) {
    
    } catch (...)  {
    
    }
    
    

    8)如果程序抛出的异常没有被捕获,程序将终止。可以对main()函数使用try-catch结构以捕获所有没有被捕获的异常;

    2 抛出列表

    C++允许指定函数或者方法可以抛出的异常。也即抛出列表。
    void readFile()
    throw(invalid_argument, runtime_error)
    {
    //code
    }
    注意:
    1)不能仅仅根据抛出列表中的不同异常重载函数;
    2)如果函数/方法没有指定抛出列表,那么可以抛出任意异常。
    3)如果不想让函数/方法抛出异常,可以使用noexcept

    void readFile() noexcept;
    

    4)函数/方法可以抛出 抛出列表之外的异常,但是会导致程序终止;

    void readFile() throw(invalid_argument, runtime_error) {
      throw 5;
    }
    
    int main() {
        try {
          readFile();
        } catch (int x) {
    
        }
        return 0;
    }
    

    上面的代码会导致程序终止。

    5)set_unexcepted
    如果出现意料之外的异常,可以使用set_unexcepted更改其行为。
    规则如下:
    (1)如果处理函数抛出一个新的异常,这个新的异常将会替换掉意料之外的异常,就像新的异常是最初被抛出的一样。
    (2)如果新抛出的异常也不在抛出列表中,程序处理如下:
    (2.1)如果抛出列表给出了bad_exception,就抛出bad_exception;
    (2.2)如果抛出列表没有给出bac_exception,就终止;
    set_unexcepted通常用于将意料之外的异常转化为预期的异常;

    void myUnexcepted() {
      throw runtime_error("");
    }
    
    int main() {
       unexcepted_handler old_handler = set_unexcepted(myUnexcepted);//保存旧的处理函数
    try {
    
    } catch (int e) {
      
    }  catch (const runtime_error& e) {
    
    }
    
    set_unexcepted(old_handler);//还原
    }
    

    由于unexcepted函数作用于整个引用程序而不是这个函数,所以当需要特殊处理程序的代码结束以后,需要还原处理程序。

    3 在重写方法中修改抛出列表

    在子类中重写虚方法时,如果想让抛出列表比父类中的抛出列表更加严格,可以修改抛出列表。
    总结为允许三种情况:
    1)删除列表中的异常(注意不是全部删除);
    2)添加超类抛出列表中异常的子类;
    3)将方法设置为noexcept;
    代码例子:

    class D {
        
    };
    class A {
        
    };
    
    class B : public A {
        
    };
    
    class C : public B {
        
    };
    
    class Foo {
    public:
        void virtual func() throw (A,D) = 0;
        
    };
    
    class Bar: public Foo {
    public:
        void virtual func() throw(A);//删除异常D,允许
        void virtual func() throw(A,D,B);//添加A的子类,允许
        void virtual func() throw(B,C);//允许
        //void virtual func() noexcept;//允许
        //void virtual func() throw(B, int);//不允许
        //void virtual func();//全部删除,不允许
    };
    
    

    4 嵌套异常

    using namespace std;
    class MyException : public exception {
    public:
        MyException(const char* msg):mMsg("") {
            mMsg = msg;
        }
        virtual ~MyException() noexcept {}
        virtual const char* what() const noexcept override {
            return mMsg.c_str();
        }
    private:
        string mMsg;
    };
    
    void doSomething() {
        try {
            throw runtime_error("runtime_error");
        } catch (const runtime_error& e) {
            cout << "catch runtime_error exception : " << e.what() << endl;
            cout <<" throw MyException :" << endl;
    throw_with_nested(MyException("Myxception"));
        }
    }
    
    
    int main(int argc, const char * argv[]) {
        // insert code here...
        try {
            doSomething();
        } catch (const MyException& e) {
            const nested_exception *p = dynamic_cast<const nested_exception*>(&e);
            if (p) {
                try {
                    p->rethrow_nested();
                } catch (const runtime_error& e) {
                    cout << "nested exceprion => " << e.what() << endl;
                }
            }
            
        }
    }
    

    执行结果:

    catch runtime_error exception : runtime_error
     throw MyException :
    nested exceprion => runtime_error
    

    备注:
    1)C++高级编程中,讲到嵌套类必须要同时继承混入类std::nested_exception,但是实际测试,不继承也是可以的。
    2) 上面使用dynamic_cast将MyException转型,然后获取嵌套类,可以使用rethrow_if_nested简化,代码如下:

    int main(int argc, const char * argv[]) {
        // insert code here...
        try {
            doSomething();
        } catch (const MyException& e) {
            
            try {
                std::rethrow_if_nested(e);
            } catch (const runtime_error& e1) {
                cout << "nested exceprion => " << e1.what() << endl;
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:C++语法系列之9-- 异常处理

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