本文整理自博文“C++的try_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 }
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 }
先看个例子
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 }
在该例子中专门设计了一个异常类来处理异常。
在博文“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 }
先看个例子:
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。
那么,在析构函数中的情况呢?我们已经知道,异常抛出之后,就要调用本身的析构函数,如果这析构函数中还有异常抛出的话,则已存在的异常尚未被捕获,会导致异常捕捉不到。
标准异常都派生自一个公共的基类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 }
原文:http://www.cnblogs.com/xiehongfeng100/p/4029573.html