栈解旋(unwinding)

异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反。这一过程称为栈的解旋(unwinding)。

demo 1

  1. #include <iostream>
  2. #include <cstdio>
  3. using namespace std;
  4.  
  5. class MyException {};
  6.  
  7. class Test
  8. {
  9. public:
  10. Test(int a = 0, int b = 0)
  11. {
  12. this->a = a;
  13. this->b = b;
  14. cout << "Test 构造函数执行" << "a:" << a << " b: " << b << endl;
  15. }
  16. void printT()
  17. {
  18. cout << "a:" << a << " b: " << b << endl;
  19. }
  20. ~Test()
  21. {
  22. cout << "Test 析构函数执行" << "a:" << a << " b: " << b << endl;
  23. }
  24. private:
  25. int a;
  26. int b;
  27. };
  28.  
  29. void myFunc() throw (MyException)
  30. {
  31. Test t1;
  32. Test t2;
  33.  
  34. cout << "定义了两个栈变量,异常抛出后测试栈变量的如何被析构" << endl;
  35.  
  36. throw MyException();
  37. }
  38.  
  39. int main()
  40. {
  41. //异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,
  42. //都会被自动析构。析构的顺序与构造的顺序相反。
  43. //这一过程称为栈的解旋(unwinding)
  44. try
  45. {
  46. myFunc();
  47. }
  48. //catch(MyException &e) //这里不能访问异常对象
  49. catch (MyException) //这里不能访问异常对象
  50. {
  51. cout << "接收到MyException类型异常" << endl;
  52. }
  53. catch (...)
  54. {
  55. cout << "未知类型异常" << endl;
  56. }
  57.  
  58. return 0;
  59. }

异常接口声明

1)为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型,例如:

void func() throw (A, B, C , D); //这个函数func()能够且只能抛出类型A B C D及其子类型的异常。

2)如果在函数声明中没有包含异常接口声明,则次函数可以抛掷任何类型的异常,例如:

void func();

3)一个不抛掷任何类型异常的函数可以声明为:

void func() throw();

4) 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用terminate函数中止程序。

传统处理错误

  1. #include <iostream>
  2. #include <cstdio>
  3. using namespace std;
  4.  
  5. // 传统的错误处理机制
  6. int myStrcpy(char *to, char *from)
  7. {
  8. if (from == NULL) {
  9. return 1;
  10. }
  11. if (to == NULL) {
  12. return 2;
  13. }
  14.  
  15. // copy时的场景检查
  16. if (*from == 'a') {
  17. return 3; // copy时错误
  18. }
  19. while (*from != '\0') {
  20. *to = *from;
  21. to++;
  22. from++;
  23. }
  24. *to = '\0';
  25.  
  26. return 0;
  27. }
  28.  
  29. int main()
  30. {
  31. int ret = 0;
  32. char buf1[] = "zbcdefg";
  33. char buf2[1024] = { 0 };
  34.  
  35. ret = myStrcpy(buf2, buf1);
  36. if (ret != 0) {
  37. switch (ret) {
  38. case 1:
  39. cout << "源buf出错!\n";
  40. break;
  41. case 2:
  42. cout << "目的buf出错!\n";
  43. break;
  44. case 3:
  45. cout << "copy过程出错!\n";
  46. break;
  47. default:
  48. cout << "未知错误!\n";
  49. break;
  50. }
  51. }
  52. cout << "buf2:\n" << buf2;
  53. cout << endl;
  54.  
  55. return 0;
  56. }

throw char*

  1. #include <iostream>
  2. #include <cstdio>
  3. using namespace std;
  4.  
  5. // throw char *
  6. void myStrcpy(char *to, char *from)
  7. {
  8. if (from == NULL) {
  9. throw "源buf出错";
  10. }
  11. if (to == NULL) {
  12. throw "目的buf出错";
  13. }
  14.  
  15. // copy时的场景检查
  16. if (*from == 'a') {
  17. throw "copy过程出错"; // copy时错误
  18. }
  19. while (*from != '\0') {
  20. *to = *from;
  21. to++;
  22. from++;
  23. }
  24. *to = '\0';
  25.  
  26. return;
  27. }
  28.  
  29. int main()
  30. {
  31. int ret = 0;
  32. char buf1[] = "abcdefg";
  33. char buf2[1024] = { 0 };
  34.  
  35. try
  36. {
  37. myStrcpy(buf2, buf1);
  38. }
  39. catch (int e) // e可以写可以不写
  40. {
  41. cout << e << "int类型异常" << endl;
  42. }
  43. catch (char *e)
  44. {
  45. cout << "char* 类型异常" << endl;
  46. }
  47. catch (...)
  48. {
  49. };
  50. cout << endl;
  51.  
  52. return 0;
  53. }

throw 类对象

  1. #include <iostream>
  2. #include <cstdio>
  3. using namespace std;
  4.  
  5. class BadSrcType {};
  6. class BadDestType {};
  7. class BadProcessType
  8. {
  9. public:
  10. BadProcessType()
  11. {
  12. cout << "BadProcessType构造函数do \n";
  13. }
  14.  
  15. BadProcessType(const BadProcessType &obj)
  16. {
  17. cout << "BadProcessType copy构造函数do \n";
  18. }
  19.  
  20. ~BadProcessType()
  21. {
  22. cout << "BadProcessType析构函数do \n";
  23. }
  24.  
  25. };
  26.  
  27. //throw 类对象 类型异常
  28. void my_strcpy3(char *to, char *from)
  29. {
  30. if (from == NULL)
  31. {
  32. throw BadSrcType();
  33. }
  34. if (to == NULL)
  35. {
  36. throw BadDestType();
  37. }
  38.  
  39. //copy是的 场景检查
  40. if (*from == 'a')
  41. {
  42. printf("开始 BadProcessType类型异常 \n");
  43. throw BadProcessType(); //会不会产生一个匿名对象?
  44. }
  45.  
  46. if (*from == 'b')
  47. {
  48. throw &(BadProcessType()); //会不会产生一个匿名对象?
  49. }
  50.  
  51. if (*from == 'c')
  52. {
  53. throw new BadProcessType; //会不会产生一个匿名对象?
  54. }
  55. while (*from != '\0')
  56. {
  57. *to = *from;
  58. to++;
  59. from++;
  60. }
  61. *to = '\0';
  62. }
  63.  
  64. int main()
  65. {
  66. int ret = 0;
  67. char buf1[] = "cbbcdefg";
  68. char buf2[1024] = { 0 };
  69.  
  70. try
  71. {
  72. //my_strcpy1(buf2, buf1);
  73. //my_strcpy2(buf2, buf1);
  74. my_strcpy3(buf2, buf1);
  75. }
  76. catch (int e) //e可以写 也可以不写
  77. {
  78. cout << e << " int类型异常" << endl;
  79. }
  80. catch (char *e)
  81. {
  82. cout << e << " char* 类型异常" << endl;
  83. }
  84.  
  85. //---
  86. catch (BadSrcType e)
  87. {
  88. cout << " BadSrcType 类型异常" << endl;
  89. }
  90. catch (BadDestType e)
  91. {
  92. cout << " BadDestType 类型异常" << endl;
  93. }
  94. //结论1: 如果 接受异常的时候 使用一个异常变量,则copy构造异常变量.
  95. /*
  96. catch( BadProcessType e) //是把匿名对象copy给e 还是e还是那个匿名对象
  97. {
  98. cout << " BadProcessType 类型异常" << endl;
  99. }
  100. */
  101. /*结论2: 使用引用的话 会使用throw时候的那个对象
  102. catch( BadProcessType &e) //是把匿名对象copy给e 还是e还是那个匿名对象
  103. {
  104. cout << " BadProcessType 类型异常" << endl;
  105. }
  106. */
  107.  
  108. //结论3: 指针可以和引用/元素写在一块 但是引用和元素不能写在一块
  109. catch (BadProcessType *e) //是把匿名对象copy给e 还是e还是那个匿名对象
  110. {
  111. cout << " BadProcessType 类型异常" << endl;
  112. delete e;
  113. }
  114.  
  115. //结论4: 类对象时, 使用引用比较合适
  116.  
  117. // --
  118. catch (...)
  119. {
  120. cout << "未知 类型异常" << endl;
  121. }
  122.  
  123. return 0;
  124. }

C++异常处理 - 栈解旋,异常接口声明,异常类型和异常变量的生命周期的更多相关文章

  1. C++基础 (10) 第十天 C++中类型转换 异常 栈解旋 io操作

    1之前内容的回顾 C语言中的类型转换(int)a  强转可读性太差了 C++把()拆分成了四种转换方式 static_cast static_cast在编译器编译阶段就进行转换了 2.dynamic_ ...

  2. 牛客网Java刷题知识点之什么是异常、异常处理的原理是什么、为什么要使用异常、异常体系、运行时异常、普通异常、自定义异常、异常链

    不多说,直接上干货! 在这个世界不可能存在完美的东西,不管完美的思维有多么缜密,细心,我们都不可能考虑所有的因素,这就是所谓的智者千虑必有一失.同样的道理,计算机的世界也是不完美的,异常情况随时都会发 ...

  3. C++异常之三 异常处理接口声明

    异常处理接口声明 1 一般为了方便程序员阅读代码,提高程序的可读性,会将函数中的异常类型声明至函数头后方,不用一行一行的找抛出内容: 2 这里要注意一点,这属于C++的标准语法,但在VS中这个操作不被 ...

  4. JAVA之旅(十)——异常的概述,Try-Catch,异常声明Throws,多异常处理,自定义异常,Throw和Throws的区别

    JAVA之旅(十)--异常的概述,Try-Catch,异常声明Throws,多异常处理,自定义异常,Throw和Throws的区别 不知不觉,JAVA之旅这个系列已经更新到第十篇了,感觉如梦如幻,时间 ...

  5. java异常处理 throw RuntimeException时不需要同时方法中声明抛出throws 异常等待调用者catch进行捕获 子父类异常问题

    package com.swift.exception1; public class Demo_Exception { public static void main(String[] args) { ...

  6. “全栈2019”Java异常第十五章:异常链详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  7. “全栈2019”Java异常第十三章:访问异常堆栈跟踪信息

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  8. “全栈2019”Java异常第一章:什么是异常?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  9. C++异常之七 标准库里的异常类

    标准库里的异常类 C++标准提供了一组标准异常类,这些类以基类 Exception 开始,标准程序库抛出的所有异常,都派生于该基类,这些类构成如图所示的异常类的派生继承关系,该基类提供一个成员函数 w ...

随机推荐

  1. 深入理解DirectByteBuffer

    介绍 最近在工作中使用到了DirectBuffer来进行临时数据的存放,由于使用的是堆外内存,省去了数据到内核的拷贝,因此效率比用ByteBuffer要高不少.之前看过许多介绍DirectBuffer ...

  2. “ML学分计划”说明书

    计划的由来 我们是一群对机器学习感兴趣的小伙伴,对于神奇的机器学习经常有"一探究竟"的冲动,却因为孤身一人学习的寂寞.亦或繁忙考试工作之余的小小拖延症,而没有持续这份对知识的渴求和 ...

  3. Dynamics CRM2016 Web API之获取查找字段的text及选项集的text

    本篇再来介绍个web api的功能,关于lookup的text这里只是略带,因为有expand,现有的web api就能实现,主要提的是选项集的text,我们通过基本的查询api查出来的字段值只带有v ...

  4. Appium移动自动化框架初探

    作者:cryanimal QQ:164166060 本文简要介绍了appnium自动化框架的架构.加载流程.支持语言.相关配置,以及元素定位工具等. 官方网站: http://appium.io Ap ...

  5. FORM执行查询的各种方法

     一.FORM调用FORM后执行查询 1.打开 APPSTAND.fmb,把 Object Groups 下的 QUERY_FIND 对象组拖动到自己的 form 中的 Object Groups ...

  6. FFmpeg的H.264解码器源代码简单分析:概述

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  7. 5、Android Service测试

    如果你在应用中使用了Service,你应该来测试这个Service来确保它正常工作.你可以创建仪表测试来验证Service的行为是否正确:比如,service保存和返回有效的数值并正常的处理数据. A ...

  8. Spark技术内幕:究竟什么是RDD

    RDD是Spark最基本,也是最根本的数据抽象.http://www.cs.berkeley.edu/~matei/papers/2012/nsdi_spark.pdf 是关于RDD的论文.如果觉得英 ...

  9. Objc中为何某些类的属性要设置为copy而不是strong?

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 不知道大家是否注意,我们再使用一些第三方类的时候大多数情况下对 ...

  10. 04 Spinner 列表选中

    <span style="font-size:18px;"> <?xml version="1.0" encoding="utf-8 ...