C++中的异常(整理自其他博文)

  本文整理自博文“C++的try_catch异常”。

   1. 一个简单例子及catch(...)的作用

 1 #include <iostream>
 2 #include <stdlib.h>
 3
 4 using namespace std;
 5
 6 double func(double x, double y)
 7 {
 8     if (y == 0)
 9     {
10         throw y;        // 抛出异常
11     }
12     return x / y;
13 }
14
15 int main()
16 {
17     double res;
18     try
19     {
20         res = func(2, 3);
21         cout << "The result of x/y is : " << res << endl;
22         res = func(4, 0);
23     }
24     catch (double)        // 捕获异常
25     {
26         cerr << "error of dividing zero.\n" << endl;;
27         exit(1);
28     }
29     catch (...)            // 类似于switch case语句中会用到的的default语句
30     {
31         cerr << "exception occurs" << endl;
32     }
33
34     return 0;
35 }

A simple example

  catch(…)能够捕获多种数据类型的异常对象,所以它提供给程序员一种对异常对象更好的控制手段,使开发的软件系统有很好的可靠性。因此一个比较有经验的程序员通常会这样组织编写它的代码模块,如下:

 1 void Func()
 2 {
 3     try
 4     {
 5         // 这里的程序代码完成真正复杂的计算工作,这些代码在执行过程中
 6         // 有可能抛出DataType1、DataType2和DataType3类型的异常对象。
 7     }
 8     catch (DataType1& d1)
 9     {
10     }
11     catch (DataType2& d2)
12     {
13     }
14     catch (DataType3& d3)
15     {
16     }
17     // 注意上面try block中可能抛出的DataType1、DataType2和DataType3三
18     // 种类型的异常对象在前面都已经有对应的catch block来处理。但为什么
19     // 还要在最后再定义一个catch(…) block呢?这就是为了有更好的安全性和
20     // 可靠性,避免上面的try block抛出了其它未考虑到的异常对象时导致的程
21     // 序出现意外崩溃的严重后果,而且这在用VC开发的系统上更特别有效,因
22     // 为catch(…)能捕获系统出现的异常,而系统异常往往令程序员头痛了,现
23     // 在系统一般都比较复杂,而且由很多人共同开发,一不小心就会导致一个
24     // 指针变量指向了其它非法区域,结果意外灾难不幸发生了。catch(…)为这种
25     // 潜在的隐患提供了一种有效的补救措施。
26     catch (…)
27     {
28     }
29 }

   2. 异常中采用面向对象的处理

  先看个例子

 1 #include <iostream>
 2 #include <exception>
 3
 4 using namespace std;
 5
 6 class ExceptionClass
 7 {
 8 public:
 9
10     ExceptionClass(char * name = "Exception Default Class")
11     {
12         cout << "Exception Class : Construct String" << endl;
13     }
14
15     virtual ~ExceptionClass()
16     {
17         cout << "Exception Class : Destruct String" << endl;
18     }
19
20     void ReportError()
21     {
22         cout << "Exception Class : Report Error Message" << endl;
23     }
24
25 };
26
27 class TestedClass
28 {
29 public:
30
31     TestedClass(char * name = "dufault name")
32     {
33         cout << "Construct String::" << name << endl;
34         this->name = name;
35     }
36
37     virtual ~TestedClass()
38     {
39         cout << "Destruct String" << endl;
40     }
41
42     void mythrow()
43     {
44         throw ExceptionClass("my throw");
45     }
46
47 private:
48     char * name;
49
50 };
51
52 int main()
53 {
54     TestedClass e("Test");
55     try
56     {
57         e.mythrow();
58     }
59     catch (ExceptionClass eTestedClass)
60     {
61         eTestedClass.ReportError();
62     }
63     catch (...)
64     {
65         cout << "*******************" << endl;
66     }
67
68     return 0;
69 }

View code

  在该例子中专门设计了一个异常类来处理异常。

  在博文“C++的try_catch异常”中,作者还提供了另一个很值得参考的例子。

 1 void OpenFile(string f)
 2 {
 3     try
 4     {
 5         // 打开文件的操作,可能抛出FileOpenException
 6     }
 7     catch (FileOpenException& fe)
 8     {
 9         // 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数
10         // 正常返回;否则必须重新抛出这个异常,以供上层的调用函数来能再次处
11         // 理这个异常对象
12         int result = ReOpenFile(f);
13         if (result == false) throw;
14     }
15 }
16
17 void ReadFile(File f)
18 {
19     try
20     {
21         // 从文件中读数据,可能抛出FileReadException
22     }
23     catch (FileReadException& fe)
24     {
25         // 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数
26         // 正常返回;否则必须重新抛出这个异常,以供上层的调用函数来能再次处
27         // 理这个异常对象
28         int result = ReReadFile(f);
29         if (result == false) throw;
30     }
31 }
32
33 void WriteFile(File f)
34 {
35     try
36     {
37         // 往文件中写数据,可能抛出FileWriteException
38     }
39     catch (FileWriteException& fe)
40     {
41         // 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数
42         // 正常返回;否则必须重新抛出这个异常,以供上层的调用函数来能再次处理这个异常对象
43         int result = ReWriteFile(f);
44         if (result == false) throw;
45     }
46 }
47
48 void Func()
49 {
50     try
51     {
52         // 对文件进行操作,可能出现FileWriteException、FileWriteException
53         // 和FileWriteException异常
54         OpenFile(…);
55         ReadFile(…);
56         WriteFile(…);
57     }
58     // 注意:FileException是FileOpenException、FileReadException和FileWriteException
59     // 的基类,因此这里定义的catch(FileException& fe)能捕获所有与文件操作失败的异
60     // 常。
61     catch (FileException& fe)
62     {
63         ExceptionInfo* ef = fe.GetExceptionInfo();
64         cout << “操作文件时出现了不可恢复的错误,原因是:” << fe << endl;
65     }
66 }

   3. 构造和析构函数中的异常抛出

  先看个例子:

 1 #include <iostream>
 2 #include <stdlib.h>
 3
 4 using namespace std;
 5
 6 class ExceptionClass
 7 {
 8 public:
 9
10     ExceptionClass()
11     {
12         cout << "Construct." << endl;
13         s = new char[4];
14         cout << "Throw a exception." << endl;
15         throw 18;
16     }
17     ~ExceptionClass()
18     {
19         cout << "Destruct." << endl;
20         delete[] s;
21     }
22
23 private:
24
25     char* s;
26
27 };
28
29 void main()
30 {
31     try
32     {
33         ExceptionClass e;
34     }
35     catch (...)
36     {
37     }
38 }

  程序运行结果为:

  Construct.

  Throw a exception.

  在这两句输出之间,我们已经给 s 分配了内存,但内存没有被释放(因为它是在析构函数中释放的)。应该说这符合实际现象,因为对象没有完整构造。

  为了避免这种情况,我想你也许会说:应避免对象通过本身的构造函数涉及到异常抛出。即:既不在构造函数中出现异常抛出,也不应在构造函数调用的一切东西中出现异常抛出。但是在C++中可以在构造函数中抛出异常,经典的解决方案是使用STL的标准类auto_ptr。

  那么,在析构函数中的情况呢?我们已经知道,异常抛出之后,就要调用本身的析构函数,如果这析构函数中还有异常抛出的话,则已存在的异常尚未被捕获,会导致异常捕捉不到。

    4. 标准C++异常类

  标准异常都派生自一个公共的基类exception。基类包含必要的多态性函数提供异常描述,可以被重载。下面是exception类的原型:

1 class exception
2 {
3 public:
4     exception() throw();
5     exception(const exception&) throw();
6     exception& operator= (const exception&) throw();
7     virtual ~exception() throw();
8     virtual const char* what() const throw();
9 };

  其他派生自基类exception的标准异常类为:

 1 namespace std
 2 {
 3     //exception派生
 4     class logic_error;         //逻辑错误,在程序运行前可以检测出来
 5
 6     //logic_error派生
 7     class domain_error;        //违反了前置条件
 8     class invalid_argument;   //指出函数的一个无效参数
 9     class length_error;        //指出有一个超过类型size_t的最大可表现值长度的对象的企图
10     class out_of_range;        //参数越界
11     class bad_cast;            //在运行时类型识别中有一个无效的dynamic_cast表达式
12     class bad_typeid;         //报告在表达试typeid(*p)中有一个空指针p
13
14     //exception派生
15     class runtime_error;      //运行时错误,仅在程序运行中检测到
16
17     //runtime_error派生
18     class range_error;         //违反后置条件
19     class overflow_error;      //报告一个算术溢出
20     class bad_alloc;           //存储分配错误
21
22 }
  一个利用标准异常类的例子如下:

 1 #include <iostream>
 2 #include <exception>
 3
 4 using namespace std;
 5
 6 class TestedClass
 7 {
 8 public:
 9
10     TestedClass(char * name = "dufault name")
11     {
12         cout << "Construct String::" << name << endl;
13         this->name = name;
14     }
15
16     virtual ~TestedClass()
17     {
18         cout << "Destruct String" << endl;
19     }
20
21     void mythrow()
22     {
23         throw logic_error("my throw");
24     }
25
26 private:
27     char * name;
28
29 };
30
31 int main()
32 {
33     TestedClass e("Test");
34     try
35     {
36         e.mythrow();
37     }
38     catch (logic_error& e)
39     {
40         cerr << "logic error exception caught: " << e.what() << endl;
41     }
42     catch (exception& e)
43     {
44         cerr << "exception caught!" << e.what() << endl;
45     }
46     catch (...)
47     {
48         cout << "*******************" << endl;
49     }
50
51     return 0;
52 }

 
时间: 2024-08-10 00:05:09

C++中的异常(整理自其他博文)的相关文章

Java开发中常见异常整理

算术异常类:ArithmeticExecption 空指针异常类:NullPointerException 类型强制转换异常:ClassCastException 数组负下标异常:NegativeArrayException 数组下标越界异常:ArrayIndexOutOfBoundsException 违背安全原则异常:SecturityException 文件已结束异常:EOFException 文件未找到异常:FileNotFoundException 字符串转换为数字异常:NumberF

夯实Java基础系列10:深入理解Java中的异常体系

目录 为什么要使用异常 异常基本定义 异常体系 初识异常 异常和错误 异常的处理方式 "不负责任"的throws 纠结的finally throw : JRE也使用的关键字 异常调用链 自定义异常 异常的注意事项 当finally遇上return JAVA异常常见面试题 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 - Java异常 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.c

Laravel 5.4 中的异常处理器和HTTP异常处理实例教程

错误和异常是处理程序开发中不可回避的议题,在本地开发中我们往往希望能捕获程序抛出的异常并将其显示打印出来,以便直观的知道程序在哪里出了问题并予以解决,而在线上环境我们不希望将程序错误或异常显示在浏览器中(出于安全考虑),这个时候我们仍然要捕获异常,只不过不是显示到浏览器中,而是记录到日志中,方便日后排查问题. 百牛信息技术bainiu.ltd整理发布于博客园 Laravel当然支持PHP原生的错误和异常处理,但是在此基础上进行了一些封装处理,从而更方便在不同开发环境切换以及对错误和异常的处理.

java中反射学习整理

转载请注明:http://blog.csdn.net/j903829182/article/details/38405735 反射主要是指程序可以访问,检测和修改它本身的状态或行为的一种能力. java中反射是一种强大的工具,它能够创建灵活的代码,这些代码可以在运行时装载,无须在组件之间进行链接.反射允许在编写与执行时,使程序能够接入到jvm中的类的内部信息,而不是源代码中选定的类协作的代码.这使反射成为构建灵活应用代码的主要工具.需要注意的是,如果使用不当,反射的成本会很高. package

【PLSQL】Oracle中的异常

一.摘要 在PLSQL程序开发过程中,很重要的部分就是对程序异常的监控和处理,包括如何触发异常,何时进行处理,如何进行处理,是否将程式中的所有异常集中在一起,通过公共异常处理的procedure或function,如果没有完善的程式处理机制,很难说该程式是一只健壮的程式,当程式遇到很多类型或者量很多资料时,系统若没有异常处理必然会导致程式的出错 当预判到了某些异常,需要对预判到的异常进行合适相应的处理,是否抛出异常还是忽略还是其他 当然程式没有预判到或者是一些未知的异常遇到,所以异常处理模块也要

[C++11 并发编程] 16 在期望中保存异常

如果在异步线程中发生了异常,等待期望的线程如何才能知道并且正确的处理异常呢? 假设有如下所示的一个求平方根的函数: double square_root(double x) { if(x<0) { throw std::out_of_range("x<0"); } return sqrt(x); } 通常,如果在当前线程上下文中调用square_root(),方法如下: double y=square_root(-1); 在异步线程中调用square_root(),方法如下

Java中的异常和处理详解

原文出处:代码钢琴家 简介 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常.异常发生时,是任程序自生自灭,立刻退出终止,还是输出错误给用户?或者用C语言风格:用函数返回值作为执行状态?. Java提供了更加优秀的解决办法:异常处理机制. 异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰. Java中的异常可以是函数中的语句执行时引发的,也可以是程序员通过throw 语句手

编写高质量代码改善C#程序的157个建议——建议66:正确捕获多线程中的异常

建议66:正确捕获多线程中的异常 多线程的异常处理需要采用特殊的方式.一下这种方式会存在问题: try { Thread t = new Thread((ThreadStart)delegate { throw new Exception("多线程异常"); }); t.Start(); } catch (Exception error) { MessageBox.Show(error.Message + Environment.NewLine + error.StackTrace);

WCF中的异常

   一.考虑到安全因素,为了避免将服务端的异常发送给客户端.默认情况下,服务端出现异常会对异常屏蔽处理后,再发送到客户端.所以客户端捕捉到的异常都是同一个FaultException异常. 例如在服务端直接产生一个空引用异常,客户端捕获到的是上述异常. 服务端: class Program { static void Main(string[] args) { ServiceHost host = new ServiceHost(typeof(SayHello)); host.AddServi