C++中的异常处理

技术交流QQ群:1027579432,欢迎你的加入!

1.Cpp中的异常处理

  • 异常是程序在执行期间产生的问题。C++异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。异常提供了一种转移程序控制权的方式。C++异常处理涉及到三个关键字:try、catch、throw
    • throw: 当问题出现时,程序会抛出一个异常,这是通过使用throw关键字来完成的。
    • catch: 在想要处理问题的地方,通过异常处理程序捕获异常,catch关键字用于捕获异常。
    • try: try块中的代码标识将被激活的特定异常,它后面通常跟着一个或多个catch块。
  • 如果有一个块抛出一个异常,捕获异常的方法会使用try和catch关键字。try块中放置可能抛出异常的代码,try块中的代码被称为保护代码。如果try块在不同的情境下会抛出不同的异常,这个时候可以尝试罗列多个catch语句,用于捕获不同类型的异常。使用try/catch语句的语法如下所示:
        try{
            // 保护代码
        }catch(ExceptionName1 e1){
            // catch块1
        }catch(ExceptionName2 e2){
            // catch块2
        }catch(ExceptionNamen en){
            // catcth块n
        }
    

2.抛出异常

  • 可以使用throw语句在代码块中的任何地方抛出异常。throw语句的操作数可以是任意的表达式,表达式的结果的类型决定了抛出的异常的类型。以下是尝试除以零时抛出异常的实例:
        double division(int a, int b){
        if(b == 0)
            throw "Division by zero condition!";
        return (a / b);
        }
    
        int main(){
            int a = 3;
            int b = 0;
            cout << "division(3, 0) = " << division(a, b) << endl;
            return 0;
        }
    

3.捕获异常

  • catch块跟在try块后面,用于捕获异常。可以指定想要捕捉的异常类型,这是由catch关键字后的括号内的异常声明决定的。
        try{
            // 保护代码
        }catch(ExceptionName e){
            // 处理异常的代码
        }
    
  • 上面的代码会捕获一个类型为ExceptionName的异常。如果想让catch块能够处理try块抛出的任何类型的异常,则必须在异常声明的括号内使用省略号...,如下所示:
        double division(int a, int b){
        if(b == 0)
            throw "Division by zero condition!";
        return (a / b);
        }
        
        try{
            // 保护代码
        }catch(...){
            // 能处理任何异常的代码
        }
    
  • 下面是一个实例,抛出一个除以零的异常,并在catch块中捕获该异常
        try{
                z = division(3, 0);
            }catch(const char* msg){  // 常指针,等价于 char const *msg;
                cerr << msg << endl;
            }
    
  • 由于抛出了一个异常类型为const char*的异常,因此,当捕获该异常时,必须在catch块中使用const char*。当上面的代码被编译和执行时,它会产生下列结果:Division by zero condition!

4.Cpp中标准的异常

  • C++提供了一系列标准的异常,定义在<exception>中,可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:


    基类-派生类异常组织结构.png
  • 下表是对上面层次结构中出现的每个异常的说明:


    详细说明.png

5.定义新的异常

  • 可以通过继承和重载exception类来定义新的异常。下面的实例演示了如何使用std::exception类来实现自己的异常:
        #include "iostream"
        #include "exception"
    
    
        using namespace std;
    
        // 自定义新的异常
        struct MyException: public exception{
            const char * what() const throw(){  // what()是异常类提供的一个公共方法,它已被所有子异常类重载,这将会返回异常产生的原因。
                return "C++ Exception!";
            }
        };
        try{
            throw MyException();
        }catch(MyException &e){
            cout << "MyException caught: ";
            cout << e.what() << endl; 
        }
    
  • what()是异常类提供的一个公共方法,它已被所有子异常类重载,这将会返回异常产生的原因。
  • const throw()不是函数,这个东西叫异常规格说明,表示what函数可以抛出异常的类型,类型说明放到()里,这里面没有类型,就是声明这个函数不抛出异常;通常函数不写后面的就表示函数可以抛出任何类型的异常
  • 异常规格说明:
    • 异常规格说明的目的是为了让函数使用者知道该函数可能抛出的异常有哪些。可以在函数的声明中列出这个函数可能抛掷的所有异常类型。例如:
          void fun() throw(A, B, C, D);
      
    • 若无异常接口声明,则此函数可以抛掷任何类型的异常
    • 不抛掷任何类型异常的函数声明如下:
          // 基类
          class MyException{
              public:
                  MyException(const char * msg): message(msg){
                      cout << "构造函数MyException类的对象.....\n";
                  }
                  MyException(const MyException &other): message(other.message){
                      cout << "拷贝构造函数MyException类的对象......\n";
                  }
                  // 析构函数
                  virtual ~MyException(){
                      cout << "~MyException.....\n";
                  }
      
                  const char *what() const{
                      return message.c_str();
                  }
              private:
                  string message;
          };
          // 派生类
          class MyExceptionD: public MyException{
              public:
                  MyExceptionD(const char *message): MyException(message){
                      cout << "构造函数MyExceptionD类的对象......\n";
                  }
                  MyExceptionD(const MyExceptionD & other): MyException(other){
                      cout << "拷贝构造函数MyExceptionD类的对象......\n";
                  }
                  // 析构函数
                  ~MyExceptionD(){
                      cout << "~MyExceptionD......\n";
                  }
          };
      
          void fun(int n) throw(int,  MyException, MyExceptionD){
              if(n == 1)
                  throw 1;
              else if(n == 2)
                  throw MyException("Test Exception......");
              else if(n == 3)
                  throw MyExceptionD("Test MyExceptionD......");
          }   
      
          void fun2() throw(){
      
          }
      
          try{
          fun(2);
          }catch(int n){
              cout << "catch int......\n";
              cout << "n = " << n << endl;
          }catch(MyExceptionD &e){
              cout << "catch MyExceptionD......\n";
              cout << e.what() << endl;
          }catch(MyException &e){
              cout << "catch MyException......\n";
              cout << e.what() << endl;
          }
      
  • 在C++11中,声明一个函数不可以抛出任何异常使用关键字noexcept,见下面的实例:
        void mightThrow(); // could throw any exceptions.
        void doesNotThrow() noexcept; // does not throw any exceptions.
    
  • 下面两个函数声明的异常规格在语义上是相同的,都表示函数不抛出任何异常。
        void old_stytle() throw();
        void new_style() noexcept;
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,076评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,658评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,732评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,493评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,591评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,598评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,601评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,348评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,797评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,114评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,278评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,953评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,585评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,202评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,180评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,139评论 2 352

推荐阅读更多精彩内容