本文讲关于C++的异常的全部东西:

绝对不让异常逃离析构函数

  • 阻止exception逃离析构函数,主要是两个原因:

    1 防止在异常处理过程中的栈展开行为时,将调用terminate函数。程序将会结束,有时候事实上错误并没有那么严重。

[插入: 什么时候会调用terminate函数呢?]

[回答 : By default, the terminate handler calls abort. But this behavior can be redefined by calling set_terminate.

This function is automatically called when no catch handler can be found for a thrown exception, or for some other exceptional circumstance that makes impossible to continue the exception handling process.

//对于一个异常没有对应的catch语句块的话,就会自己主动调用terminate函数,或者是对于一些无法处理的异常的情况时。

This function is provided so that the terminate handler can be explicitly called by a program that needs to abnormally terminate, and works even if set_terminate has not been used to set a custom terminate handler (calling abort in this case).

terminate被调用的情况:

1 当发送一个异常,而且构造函数产生异常

2 当发送一个异常,或者析构函数产生异常

3 一个静态对象的构造或者析构发送一个异常

4 以atexit注冊的函数发生异常的时候

5 自己定义一个异常,可是实际上没有异常产生的时候

6 调用缺省的unexcepted()函数时候 (unexcepted函数是由于该函数抛出了没有预期的异常)

2 能够协助确保destructor完毕它应该完毕的全部的动作。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. class myexception{};
  5.  
  6. class Session
  7. {
  8. public:
  9. Session()
  10. {
  11. logCreation();
  12. }
  13.  
  14. ~Session()
  15. {
  16. try{ //这里的try catch块是非常重要的
  17. logDestruction();
  18. }catch(...){
  19. cout << "catch exception..." << endl;
  20. }
  21. }
  22.  
  23. private:
  24. static void logCreation(){cout << "enter..." << endl;}
  25. static void logDestruction() {cout << "out..." << endl;throw myexception();}
  26. };
  27.  
  28. int main()
  29. {
  30. Session s;
  31. return 0;
  32. }

catch的子语句块 VS.函数的调用

3大类的不同:

1 exception 对象总是被复制。假设以by value的方式,甚至复制两次。

2 被抛出作为exception的对象,同意的转换操作比“被传递到函数中”的少。

3  catch子句以其出现的顺序进行匹配,也就是 “first fit”的策略, 不像函数调用的 “best fit”的策略

  • 同样点: 函数參数以及exception的传递方式都有三种: by value, by reference , by pointer,
  • 不同点: 当你调用一个函数的时候,调用完成之后控制权终于会回到该函数的调用端; 可是当你抛出一个异常的时候,控制权永远都不会回到抛出端。
  • 不同点: 函数的绑定方式,假设是传值,那么传递的是该对象的副本,假设是引用,那么直接就是绑定到该对象。可是,这对于异常是不正确的,不管你的异常的catch的參数是传值还是传引用,全部传递给该catch块的都是该对象的副本。(为什么是这样呢?由于一旦控制权离开了该函数,那么该函数的全部的局部对象都离开了生存空间,就会自己主动析构掉,那么此时传给该catch块的对象便是一个已经析构了的对象,这显然是不正确的。即使该暂时对象的生存期不只限于该函数,该结论依旧成立)。
    这里的 “exception对象总是会导致复制“的这一行为,直接导致了异常处理经常比 函数调用慢!!!
  • 当对象复制被当做一个exception的,复制行为是由对象的拷贝构造函数来运行的,这个拷贝构造函数对应于该对象的静态类型!!而不是动态类型!!比如·比如以下的代码:
  1. class Base{
  2. public:
  3. Base(){cout << "ctor in Base..." << endl;}
  4. Base(const Base &){cout << "copy ctor in Base..." << endl;}
  5. };
  6.  
  7. class Derived : public Base {
  8. public:
  9. Derived(){cout << "ctor in Derived..." << endl;}
  10. Derived(const Derived &b):Base(b){cout << "copy ctor in Derived..." << endl;}
  11. };
  12.  
  13. void f()
  14. {
  15. Derived d; // print : ctor in Base ctor in Derived
  16. Base &b = d;
  17. cout << "throw..." << endl;
  18. throw b; //copy ctor in Base
  19. }
  20.  
  21. void test()
  22. {
  23. try{
  24. f();
  25. cout << "never be here..." << endl;
  26. }catch(Base) // 假设这儿是Base,那么print: copy ctor in Base,假设是Base reference,那么不输出不论什么东西
  27. {
  28. cout << "catch..." << endl;
  29. }
  30. }
  31.  
  32. int main()
  33. {
  34. test();
  35. return 0;
  36. }
  • 由上面知道“exception对象是其它对象的副本”,这里就会出如今不同的catch块中怎样传递exception的问题!!!

下述的throw 和throw w分别来模拟catch块中的继续传递当前exception的操作.

  1. //利用throw语句继续传递当前的exception,假设直接使用throw,那么传递的是最初传递来的exception的实际类型,(test1中的throw)
  2. //假设是使用throw + catch形參的方式,那么传递的是静态类型。
  3.  
  4. class Base{
  5. public:
  6. Base(){cout << "ctor in Base..." << endl;}
  7. Base(const Base &){cout << "copy ctor in Base..." << endl;}
  8. };
  9.  
  10. class Derived : public Base {
  11. public:
  12. Derived(){cout << "ctor in Derived..." << endl;}
  13. Derived(const Derived &b):Base(b) {cout << "copy ctor in Derived..." << endl;}
  14. };
  15.  
  16. void f1()
  17. {
  18. try{
  19. Derived d; // ctor in Base , ctor in Derived
  20. Base &b = d;
  21. cout << "throw..." << endl;
  22. //此处throw的是Derived对象
  23. throw d; //copy ctor in Base , copy ctor in Derived,这里看的是静态类型的!!!
  24. }catch(Base &w) //Base&是能够捕捉到上述的Derived异常的,不管此处是Base还是Base&,都能捕获到Derived类型的异常。
  25. // 假设此处是Derived,那么上述的throw假设throw的是b,那么这里不能捕获到。与一般的函数调用的參数绑定方式是一样的。
  26. {
  27. cout << "throw current exception 1, using throw only..." << endl;
  28. throw ; //假设直接使用throw,即使上面的catch是将一个Derived对象绑定到一个Base对象,这里传递的依旧是最初的Derived对象。
  29. }
  30. }
  31.  
  32. void test1()
  33. {
  34. try{
  35. f1();
  36. cout << "never be here..." << endl;
  37. }catch(Derived) //copy ctor in Base, copy ctor in Derived
  38. //}catch(Base) // copy ctor in Base .
  39. {
  40. cout << "catch..." << endl;
  41. }
  42. }
  43.  
  44. void f2()
  45. {
  46. try{
  47. Derived d; // print : ctor in Base ctor in Derived
  48. Base &b = d;
  49. cout << "throw in f2..." << endl;
  50. throw b; //copy ctor in Base //这里的throw传递的则是静态类型。
  51. }catch(Base &w)
  52. {
  53. cout << "throw current exception 2 " << endl;
  54. throw w; //copy ctor in Base
  55. }
  56. }
  57.  
  58. void test2()
  59. {
  60. try{
  61. f2();
  62. cout << "never be here in test2..." << endl;
  63. }catch(Base &) // 假设这儿是Base,那么print: copy ctor in Base,假设是Base reference,那么不输出不论什么东西
  64. {
  65. cout << "catch in test2..." << endl;
  66. }
  67. }
  68. int main()
  69. {
  70. cout << "1 ; "<< endl;
  71. test1();
  72. cout << "2 : " << endl;
  73. test2();
  74. return 0;
  75. }

  • 不同点: 一个被抛出的对象(依据上述显然是个暂时对象)能够以 by reference的方式捕捉,不须要以一个by reference to const的方式捕捉,可是函数调用的过程中将一个暂时对象传递给一个non-const-reference參数是不同意的。可是对exception合法。

    将一个暂时对象传递给一个non-const-reference參数为什么是不同意的。 ]

    考虑以下的样例:

  1. void f(const string &s)
  2. {
  3. cout << s << endl;
  4. cout << "const-reference..." << endl;
  5. return;
  6. }
  7.  
  8. void f2(string &s)
  9. {
  10. cout << "non-const reference..." << endl;
  11. return;
  12. }
  13.  
  14. int main(void)
  15. {
  16. char buff[20] = "1234";
  17. //f和f2函数须要的是一个string的对象,可是传递的都是buff字符数组,那么这里就会有一个隐式类型转换,生成一个暂时的string对象。
  18. f(buff); //调用成功。由于是const,不须要改变什么。
  19. f2(buff); //调用失败,原因:f2须要的是string的non-const reference,也就意味着f2函数可能会改动字符串s,而此时传递给
  20. //f2的是一个string的暂时对象,在函数退出时,该实參没有改变,全部的操作均施加于暂时形參s上,显然这并非程序猿的意图,我们传递一个
  21. //non-const reference给f2,应该就是希望改动buff这个实參的。
  22. return 0;
  23. }

  • 不同点: 假设以by value的方式传递一个函数自变量,那么便是对被传递对象做一个副本,此副本存储于相应的函数參数中; 假设以 by value的方式传递exception,会怎么样呢? 比如 :

    catch (Base b) 。。。 //预期得付出 “被抛出物” 的 ”两个副本“的构造代价,一个用于 ”不论什么exception都会产生的暂时对象的“身上,另一个是 ”将暂时对象拷贝到b”。
  • 假设以by reference的方式的话,那么函数不须要不论什么额外动作,可是 exception 还是会有一个 “被抛出物”的副本的构造的代价。
  • 假设以by pointer的方式来传递exception的话,那么必须注意的是千万不要跑出一个指向局部对象的指针。这也是 “义务性复制操作”必须考虑的情况。

  • 不同点:throw子句与catch參数的匹配!!

    exception与catch子句的匹配过程只不过两种转换: 1 , 继承架构中的类转换。 (一个针对Base class exception编写的catch子句,能够捕捉到一个derived class的exception) ,注意: 这个转换规则适用于以by value, by reference,或者是by pointer的三种方式。 2、 从一个“有型指针” 转换为一个 “无型指针”,比如一个针对于: const void *设计的catch子句,能够捕捉随意的指针类型的exception。

  • 不同点: catch子句总是依出现的顺序进行匹配。也就是说,针对Derived class exception的catch子句一定要放在针对Base class exception的catch子句的前面。

Catch exception By reference

理由:

+ 假设是by pointer的话,那么须要的是一个超出该作用域都不会被销毁的对象,那么此时global和static是能够帮忙的,可是程序猿们可能会忘记这些;假设就是在throw的时候才暂时的构造一个exception对象,比方: throw new exception,那么catch子句是否要删除这个对象呢?诚然,假设是global或者static,那么显然不须要删除,可是假设是new的,显然就须要删除。

+ 假设是by value的话,就会出现对象分割的问题,当把一个Derived exception的对象给一个Base exception的时候,那么会出现对象分割的问题,这个时候假设你在catch块中调用了虚函数,那么该函数的版本号就仅仅是基类的版本号。显然这不是我们要的。

使用Catch exception by reference,便能够避免这些问题。

C++ 之 exception的更多相关文章

  1. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  2. 浅谈java异常[Exception]

    学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:589809992 我们一起学Java! 一. 异常的定义 在<java编程思想 ...

  3. Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory

    学习架构探险,从零开始写Java Web框架时,在学习到springAOP时遇到一个异常: "C:\Program Files\Java\jdk1.7.0_40\bin\java" ...

  4. Exception in thread "main" java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.<init>(I)V

    在学习CGlib动态代理时,遇到如下错误: Exception in thread "main" java.lang.NoSuchMethodError: org.objectwe ...

  5. Atitit 解决Unhandled event loop exception错误的办法

    Atitit 解决Unhandled event loop exception错误的办法 查看workspace/.metadata/.log org.eclipse.swt.SWTError: No ...

  6. Java中的Checked Exception——美丽世界中潜藏的恶魔?

    在使用Java编写应用的时候,我们常常需要通过第三方类库来帮助我们完成所需要的功能.有时候这些类库所提供的很多API都通过throws声明了它们所可能抛出的异常.但是在查看这些API的文档时,我们却没 ...

  7. Error on line -1 of document : Premature end of file. Nested exception: Premature end of file.

    启动tomcat, 出现, ( 之前都是好好的... ) [lk ] ERROR [08-12 15:10:02] [main] org.springframework.web.context.Con ...

  8. Android开发学习之路-关于Exception

    Exception在Java中是表示异常的一个类.它是Throwable的子类. 而Exception的子类RuntimeException是一个特殊的异常类,在代码中不需要对此类进行throw,而是 ...

  9. 严重: Exception sending context initialized event to listener instance of class

    问题描述:Exception sending context initialized event to listener instance of class org.springframework.w ...

  10. python之最强王者(11)——异常(exception)

    1.Python 异常处理 python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误.你可以使用该功能来调试python程序. 异常处理: 本站Python教程会具体介绍. ...

随机推荐

  1. 如何利用多核CPU来加速你的Linux命令 — awk, sed, bzip2, grep, wc等(转)

    你是否曾经有过要计算一个非常大的数据(几百GB)的需求?或在里面搜索,或其它操作——一些无法并行的操作.数据专家们,我是在对你们说.你可能有一个4核或更多核的CPU,但我们合适的工具,例如 grep, ...

  2. Hive ERROR: Out of memory due to hash maps used in map-side aggregation

    什么时候hive在运行大数据量的统计查询语句时.常常会出现以下OOM错误.详细错误提演示样例如以下: Possible error: Out of memory due to hash maps us ...

  3. DiskFileUpload类

    1.2.2 DiskFileUpload类 DiskFileUpload类是Apache文件上传组件的核心类,应用程序开发者通过这个类来与Apache文件上传组件进行交互.以下介绍DiskFileUp ...

  4. swing中几种layout示例(转)

    import java.awt.BorderLayout;import java.awt.FlowLayout;import java.awt.GridLayout;import java.awt.e ...

  5. .Net下一个Winform方案可以让MessageBox.Show它显示在父窗口的中间

    下面的文字,缺省值是在屏幕中间显示. DialogResult dr = MessageBox.Show("是否要删除此数据?", "删除确认", Messag ...

  6. OOP思想

    OOP思想 读者朋友们大家好,我们今天这一讲就接着前面的封装继续讲解,今天就是在前面内容上面的升级,OOP思想中的继承,我们就先来解释一下继承到底是什么意思,我们在什么地方会用到继续. 继承就是,后代 ...

  7. JSON小结

    在 JSON 中,“Object” 是什么呢? json.org 有很好的解释: 1 .An object is an unordered set of name/value pairs. 2.An ...

  8. Oracle 六闪回技术,flashback

    Flashback 技术基于Undo segment基于内容的, 因此,限制UNDO_RETENTON参数. 要使用flashback 特征,您必须启用自己主动撤销管理表空间. 在Oracle 11g ...

  9. SQL Server 2005,2008 正则表达式 替换函数应用详解

    CREATE function dbo.regexReplace ( @source ntext, --原字符串 ), --正则表达式 ), --替换值 , --是否是全局替换 --是否忽略大小写 ) ...

  10. mysql5.6设置主从报错1236,Increase max_allowed_packet on master,原因却是Binlog偏移量不对

    在试Mysql5.6,搭了个主从: CHANGE MASTER TO MASTER_HOST='1.2.3.4', master_user='slave', master_password='xxxq ...