首页 > 代码库 > C++中的异常(整理自其他博文)
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 try19 {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 }
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 TestedClass28 {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 try56 {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 }
在该例子中专门设计了一个异常类来处理异常。
在博文“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 try20 {21 // 从文件中读数据,可能抛出FileReadException22 }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 try36 {37 // 往文件中写数据,可能抛出FileWriteException38 }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 try51 {52 // 对文件进行操作,可能出现FileWriteException、FileWriteException53 // 和FileWriteException异常54 OpenFile(…);55 ReadFile(…);56 WriteFile(…);57 }58 // 注意:FileException是FileOpenException、FileReadException和FileWriteException59 // 的基类,因此这里定义的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 try32 {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)中有一个空指针p13 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 try35 {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 }
C++中的异常(整理自其他博文)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。