zoukankan      html  css  js  c++  java
  • 29.C++- 异常处理

    C++内置了异常处理的语法元素 try catch

    try语句处理正常代码逻辑

    • try语句发现异常时,则通过throw语句抛出异常,并退出try语句

    catch语句处理异常情况

    • throw语句抛出异常时,则会直接跳到catch语句处理
    • catch语句允许被重载,在try语句后面可以有多个catch语句
    • 不同类型的异常由不同的catch语句捕获,顺序从上往下严格匹配,不会进行隐式转换,比如:
    throw 1;       //由int型的catch语句捕获
    throw 1.5;     //由double型的catch语句捕获
    throw 1.5f;    //由float型的catch语句捕获
    throw 'A';      //由char型的catch语句捕获
    throw "ABC";    //由char const *型的catch语句捕获
    throw string("ABC");      //由string型的catch语句捕获
    • cath(...)语句,表示捕获前面所有没被定义的异常,且只能放在所有catch语句的末尾,比如:
        try
        {
                  throw 1.55;          //直接退出try语句,跳转到满足条件的catch语句
                  throw "ERR";   
        }
        catch(int i)                //只捕获int型异常
        {
                  cout<<i<<endl;
        }
        catch(string s)           //只捕获string型异常
        {
            cout<<s<<endl;
        }
        catch(...)                //捕获前面所有没被定义的异常
        {
            cout<<"cath(...)"<<endl;
        }

    运行打印:

    cath(...)

     

    throw抛出的异常必须被catch处理

    如果throw抛出的异常,在当前函数没有catch语句能捕获,则会返回到上一级函数里再寻找catch语句,直到被处理为止,否则程序将结束运行,如下图:

     

     

     

    在catch语句块中可以将捕获的异常重新抛出

    catch抛出的异常,则需要通过外层的try...catch...捕获

    如果是catch(...)语句,则直接填throw;即可,编译器会自动将捕获的异常重新抛出

    比如:

    void internal()
    {
                 try
                {
                         throw 1;
                }
                 catch(...)
                {
                         cout<< "internal: catch(...)"<<endl;
                         throw;
                }
    }
    
    int main()
    {
    
       try
       {
                 internal();      
       }
    
       catch(int i)
       {
              switch(i)
              {
                 case 1 :                                            //1对应超时
                         cout<<"timeout"<<endl;  break;
                  case 2 :                                           //2对应实参有误
                         cout<<"invalid argument"<<endl; break;
                  case 3 :                                           //3对应运行异常
                         cout<<"runtime exception"<<endl; break;
              } 
       }
       return 0;
    
    }

    运行打印:

    internal: catch(...)
    timeout

     

    catch中重新抛出异常的意义

    举个例子,当我们调用第三方库的func()函数,但是该func()函数返回的异常是int型,每个异常值意义大有不同 (每次查看异常值都需要翻看文档手册才行)

    所以我们可以在自己库创建一个myfunc()函数,通过try...catch...再次封装func()函数,将异常值重新解释为其它类型(比如const char *),然后再次抛出.

    以后调用myfunc()函数,获取的异常信息就是const char *类型了.

     

    如果catch中抛出的类型是类的情况

    • 需要将捕获子类异常的catch放在上部
    • 捕获父类异常的cath放在下部, 避免子类异常当做父类异常来使用.

    比如:

    #include <iostream>
    #include <string>
    using namespace std; class Base { };
    class Exception : public Base { int m_id; //异常值 string m_desc; //异常值描述信息 public: Exception(int id, string desc) { m_id = id; m_desc = desc; }
    int id() const { return m_id; }
    string description() const { return m_desc; } }; /* 假设: 当前的函数式第三方库中的函数,因此,我们无法修改源代码 函数名: void func(int i) 抛出异常的类型: int -1 ==》 参数异常 -2 ==》 运行异常 -3 ==》 超时异常 */ void func(int i) { if( i < 0 ) { throw -1; } if( i > 100 ) { throw -2; } if( i == 11 ) { throw -3; } cout << "Run func..." << endl; } void MyFunc(int i) { try { func(i); } catch(int i) { switch(i) { case -1: throw Exception(-1, "Invalid Parameter"); //生成一个子类对象,并抛出 break; case -2: throw Exception(-2, "Runtime Exception"); break; case -3: throw Exception(-3, "Timeout Exception"); break; } } } int main(int argc, char *argv[]) { try { MyFunc(11); } catch(const Exception& e) //捕获子类异常的catch放在上部 { cout << "Exception Info: " << endl; cout << " ID: " << e.id() << endl; cout << " Description: " << e.description() << endl; } catch(const Base& e) //捕获父类异常的catch放在下部 { cout << "catch(const Base& e)" << endl; } return 0; }

    运行打印:

    Exception Info:
       ID: -3
       Description: Timeout Exception

    在C++标准库中提供了异常类

    头文件 : <stdexcept>

    标准库中的异常都是从exception类派生的

    exception类主要有两个分支

    - logic_error

    用于程序中可避免的逻辑错误,在程序运行之前,就能被检测到

    logic_error类派生了以下几种类:

    • domain_error(const string& )    :   专业领域内的范畴
    • invalid_argument(const string& )   :  无效参数,比如对unsigned型进行负数操作
    • length_error(const string& )  :    长度异常,比如字符串附加太多字符
    • out_of_range(const string&)     :    超出范围,比如数组下标越界
    • 它们都有一个what()成员函数,用来返回一个字符串异常信息

     

    -runtime_error

    常用于程序中无法避免的恶性错误,只在程序运行时才能被检测到

    logic_error类派生了以下几种类:

    • range_error(const string& )  :内部计算时发生区间错误
    • overflow_error(const string& )  :算数运算时发生上溢
    • underflow_error(const string& )  :算数运算时发生下溢
    • 它们都有一个what()成员函数,用来返回一个字符串异常信息

    比如:

    #include <iostream> 
    #include <stdexcept>
    using namespace std; template <typename T, int N > class Array { T ma[N];public: Array() { for(int i=0;i<N;i++) ma[N]=0; } T& operator [] (int index) { if((index>=0)&&(index<N)) { return ma[index]; } else //数组下标越界 { throw out_of_range("T& operator [] (int index)"); //抛出一个 out_of_range类 } } }; int main() { try { Array<int,5> arr; arr[10]=100; } catch(out_of_range& exc) { cout<< exc.what()<<endl; //打印捕获到out_of_range类的异常信息 cout<< " Line: " << __LINE__ <<", Function: "<< __FUNCTION__ << endl; //打印当前行 } return 0; }

    运行打印:

    T& operator [] (int index)
    Line: 41, Function: main

     

  • 相关阅读:
    redis-mysql连接池
    Java并发编程原理
    利用MyBatis生成器自动生成实体类、DAO接口和Mapping映射文件
    Tomcat 启动图解
    JVM
    Java中的Exception
    Java 设计模式六原则及23中常用设计模式
    Jquery15 插件
    Jquery14 工具函数
    Jquery13 Ajax 进阶
  • 原文地址:https://www.cnblogs.com/lifexy/p/8832424.html
Copyright © 2011-2022 走看看