鱼C论坛

 找回密码
 立即注册
查看: 1891|回复: 0

[学习笔记] 041-C++之异常处理

[复制链接]
发表于 2018-9-13 22:12:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 moc 于 2018-9-13 22:12 编辑

1、异常的简介
    异常是程序在执行期间产生的问题,提供的一种转移程序控制权的机制,与函数机制独立和互补。
函数是一种以站结构展开的上下函数衔接的程序控制系统,异常是另一种控制结构,它依附于栈的结构,却可以同时设置多个异常作为网捕条件,以类型匹配在栈机制中跳跃回馈。
    C++ 异常处理涉及到三个关键字:try、catch、throw。
异常处理的基本思想:
        未命名文件.jpg
1. C++的异常处理机制使得异常的引发异常处理不必在一个函数中,这样底层函数可以着重解决具体的问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计针对不同类型的异常处理
2. 异常是专门针对抽象编程的一系列错误处理,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法跳跃,但错误处理机制遇到错误可以转到若干级之上进行错误处理。
086.jpg
3. 异常超脱于函数机制,决定了其对函数的跨越式回跳。即异常跨越函数。
2、异常的基本语法
  1. throw  表达式;    // 抛出异常
  2. //捕获并处理异常
  3. try
  4. {
  5.    // 保护代码
  6. }catch( ExceptionName e1 )
  7. {
  8.    // catch 块
  9. }catch( ExceptionName e2 )
  10. {
  11.    // catch 块
  12. }catch( ... )  //其他未知异常
  13. {
  14.    // catch 块
  15. }
复制代码

1.  若有异常则通过throw操作创建一个异常对象并抛掷
2.  将可能抛出的异常的程序嵌在try块中,try块内为保护代码。
3.  catch子句在try之后,按顺序进行检查,匹配捕获并进行异常处理(或继续抛异常);
4.  try语句没有发生异常,则跳过catch子句继续向下执行;
5.  如果没有找到匹配的catch,即抛出的异常无人接受,激发最后一道防线,terminate函数(可修改),该函数引起运行终止和abort函数。
6. 类的构造函数无返回类型,不能通过返回值报告运行状态,可通过异常解决。
7. 异常机制与函数机制互不干涉,异常的捕捉方式是基于类型匹配捕捉相当于函数返回类型匹配,而不是函数参数匹配,所以捕捉不用考虑一个抛掷中的多种数据类型匹配问题。
8. 异常匹配严格按照类型匹配。匹配苛刻程度与模板一样,不允许隐式类型转换。
  1. void divide(int x, int y)
  2. {
  3.         if (y == 0)    // 0为除数
  4.         {
  5.                 throw x;   // 抛出 int类型  异常
  6.         }
  7.         cout << "Divide结果:" << x / y << endl;
  8. }

  9. void myDivide0(int x, int y)
  10. {
  11.         divide(x, y);
  12. }

  13. // 发生的异常必须在函数中处理,否者会产生函数中断
  14. int main()
  15. {
  16.         try
  17.         {
  18.                 myDivide0(10, 2);
  19.                 myDivide0(123, 0);
  20.         }

  21.         catch (int e)   // 捕获int型异常
  22.         {
  23.                 cout << e << "被零除" << endl;
  24.         }

  25.         catch (...)   // 捕获漏网之鱼
  26.         {
  27.                 cout << "其他未知的异常!" << endl;
  28.                 cout << "我接受了异常,但我没有处理,我继续往外扔";
  29.                 throw;
  30.         }

  31.         system("pause");
  32.         return 0;
  33. }
复制代码

3、栈解旋
异常抛出后,从进入try块起到异常被抛出前,这期间在栈上的构造的所有对象都会被析构,析构的顺序和构造的顺序相反,这一过程即  栈解旋
函数抛出异常限定,可以在定义函数之后加throw说明。
  1. class Test
  2. {
  3. public:
  4.         Test(int a = 0, int b = 0)
  5.         {
  6.                 this->a = a;
  7.                 this->b = b;
  8.                 cout << "构造函数do\n";
  9.         }
  10.         ~Test()
  11.         {
  12.                 cout << "析构函数do\n";
  13.         }
  14. private:
  15.         int a;
  16.         int b;
  17. };

  18. void myDivide()
  19. {
  20.         Test t1(1, 2), tr2(3, 4);  // 测试t1,t2的析构顺序
  21.         cout << "myDivide...发生异常\n";
  22.         throw Test();
  23. }

  24. void myDivide12() throw (int , char, char*)  //该函数只能抛出int,char,char*类型的异常
  25. {
  26.         throw Test();
  27. }

  28. void myDivide2() throw()  // 该函数不会抛出任何异常
  29. {
  30.         throw Test();  // 非要抛出时有警告。
  31. }

  32. int main()
  33. {
  34.         try
  35.         {
  36.                 myDivide();
  37.         }
  38.         catch (int a)
  39.         {
  40.                 cout << "int类型 异常\n";
  41.         }
  42.         catch (...)
  43.         {
  44.                 cout << "未知 异常\n";
  45.         }

  46.         system("pause");
  47.         return 0;
  48. }
复制代码

4、异常变量的生命周期
throw “aaa”;  是抛出的char*类型。
对于抛出类对象:
1.  如果  接受异常的时候  使用一个异常变量,则执行copy构造函数构造异常变量;
2.  使用引用的话  会直接使用throw时候的那个对象
3.  使用指针接的话,如果抛出时不new一个对象的话,会形成参野指针;
最终结论:类对象发生异常时,使用引用比较合适
  1. class BadSrcType {};
  2. class BadDestType {};
  3. class BadProcessType
  4. {
  5. public:
  6.         BadProcessType()
  7.         {  cout << "BadProcessType构造函数do\n";  }

  8.         BadProcessType(BadProcessType &obj)
  9.         {  cout << "BadProcessType拷贝函数do\n";  }

  10.         ~BadProcessType()
  11.         {  cout << "BadProcessType析构函数do\n";  }
  12. };

  13. // throw  类对象 类型异常
  14. void my_strcpy(char* to, char*from)
  15. {
  16.         if (from == NULL)
  17.         {
  18.                 throw BadSrcType();
  19.         }
  20.         if (to == NULL)
  21.         {
  22.                 throw BadDestType();
  23.         }

  24.         // copy时 场景检查
  25.         if (*from == 'a')
  26.         {
  27.                 cout << "开始BadProcessType类型异常\n ";
  28.                 throw BadProcessType();
  29.         }

  30.         if (*from == 'b')
  31.         {
  32.                 cout << "开始BadProcessType类型异常\n ";
  33.                 throw &(BadProcessType());
  34.         }

  35.         if (*from == 'c')
  36.         {
  37.                 cout << "开始BadProcessType类型异常\n ";
  38.                 throw new BadProcessType;
  39.         }

  40.         while (*from != 0)
  41.         {
  42.                 *to++ = *from++;
  43.         }
  44.         *to = '\0';
  45. }


  46. int main()
  47. {
  48.         int ret = 0;
  49.         char buf1[] = "asdfghjkl";
  50.         char buf2[128] = { 0 };

  51.         try
  52.         {
  53.                 my_strcpy(buf2, buf1);
  54.         }
  55.         catch (int e)
  56.         {
  57.                 cout << e << "int类型异常\n";
  58.         }
  59.         catch (char* e)
  60.         {
  61.                 cout << e << "char*类型异常\n";
  62.         }
  63.         catch (BadSrcType e)
  64.         {
  65.                 cout << "BadSrcType类型异常\n";
  66.         }
  67.         catch (BadDestType e)
  68.         {
  69.                 cout << "BadDestType类型异常\n";
  70.         }
  71.         //结论1:如果  接受异常的时候  使用一个异常变量,则执行copy构造函数构造异常变量
  72.         catch (BadProcessType e)
  73.         {
  74.                 cout << "BadProcessType类型异常\n";
  75.         }
  76.         //结论2:使用引用的话  会使用throw时候的那个对象
  77.         //catch (BadProcessType &e)
  78.         //{
  79.         //        cout << "BadProcessType类型异常\n";
  80.         //}
  81.         //结论3:指针可以和引用写在一块,但引用/元素不能写在一块
  82.         catch (BadProcessType *e)
  83.         {
  84.                 cout << "BadProcessType指针类型异常\n";
  85.                 delete e;
  86.         }
  87.         catch (...)
  88.         {
  89.                 cout << "出现未知异常!\n";
  90.         }
  91.         // 最终结论:类对象发生异常时,使用引用比较合适
  92.         system("pause");
  93.         return 0;
  94. }
复制代码

5、异常的层次结构
  即继承在异常中的应用
对于同一种类型的异常;异常派生,按引用传递异常。
6、C++ 标准的异常
        C++ 提供了一系列标准的异常,定义在 <exception> 中,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:
360截图20180913221117874.jpg
传送门

  

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-22 10:50

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表