Cpp深入:异常体系结构

1. 异常简介

2. 函数异常列表

3. 堆栈解退

4. 标准库exception类型简介

5. 继承中的异常

6. 异常何时迷失?

7. 异常处理最佳实践

1. 异常简介

c++中的异常使用关键字try{} catch(Type ){}来捕获。可以使用throw关键字抛出异常。如果在程序执行过程中出现了未捕获的异常的话 ,默认的情况是终止程序的运行。

  1. int main()  
  2. {  
  3.     try  
  4.     {  
  5.         // 这里可以抛出class或者是简单类型:字符串,int等  
  6.         throw "exception";  
  7.     }  
  8.     catch(const char* err)  
  9.     {  
  10.         // 选择异常处理或者是   
  11.         cout << err << endl;  
  12.       
  13.         // 如果异常是无法处理的话,选择重新抛出异常  
  14.         // throw;  
  15.     }  
  16.     return 0;  
  17. }  

 

2. 函数异常列表

函数异常列表指明了该函数可能抛出的异常的类型,如果函数引发了除了函数异常列表之外的异常,那么默认的情况是调用终止程序运行。如果程序想要执行终止程序运行的话 ,可以使用abort函数和exit函数,exit函数刷新io缓冲区,abort函数不刷新。同时exit和abort函数将不会调用堆栈中的变量的析构函数。

  1. void throwExxceptionFunc() throw(const char*, double, bad_cast)  
  2. {  
  3. }  

 

3. 堆栈解退

如下图所示,如果在深层嵌套的函数中发生异常,那么程序将不断释放堆栈中的内存,直到能够找到一个合适的catch块来捕获该异常,这个过程中堆栈对象的类的析构函数将被调用。


4. 标准库exception类型简介

cpp标准库中提供了一系列的异常类。在<exception>头文件中包含:exception,bad_exception,bad_alloc异常类型的定义,<stdexcept>文件中定义了logic_error,domain_error,invalid_argumentlength_error,out_of_range,runtime_error,overflow_error等异常,我们可以选择一个合适的类型来继承,从而实现自定义异常类型。


  1. class MyRuntimeException : public runtime_error  
  2. {  
  3.     // 构造函数  
  4.     MyRuntimeException(const string& msg) : runtime_error(msg)  
  5.     {  
  6.     }  
  7.     // 析构函数  
  8.     ~MyRuntimeException()  
  9.     {  
  10.     }  
  11.     const char* what() const  
  12.     {  
  13.         return runtime_error::what();  
  14.     }  
  15. };  

 

5. 继承中的异常

如果子类重写了父类的某个方法的话,那么需要保证子类的该方法的函数异常列表需要和父类的相同或者是继承的关系(vc没有实现该特性,可能出现忽略 C++ 异常规范,但指示函数不是 __declspec(nothrow)警告)。

  1. class Base  
  2. {  
  3. public:  
  4.     virtual void func() throw(exception) { }  
  5. };  
  6. class Sub : public Base  
  7. {  
  8.     void func() throw(runtime_error)  
  9.     {  
  10.     }  
  11. };  

 

6. 异常何时迷失?

意外unexpected异常:如何函数抛出了未在函数异常列表中的异常类型的话,将引发意外异常。默认将调用unexpected函数。

未捕获异常:异常已经引发,但是没有catch块来处理该异常。默认是调用terminate函数。

上面两种情况默认都是终止程序运行,但是可以设置出现上面两种情况后调用的处理函数handler function。

  1. // 异常处理  
  2. #include <iostream>  
  3. #include <exception>  
  4. using namespace std;  
  5. void my_terminate()  
  6. {  
  7.     cout << "in my_terminate" << endl;  
  8. }  
  9. int main()  
  10. {  
  11.     set_terminate(my_terminate);  
  12.       
  13.     throw exception("exception");  
  14.     return 0;  
  15. }  

 

下面的代码将在vc(vs2008)中无法运行,vc没有实现函数异常列表特性。

  1. // 异常处理  
  2. #include <iostream>  
  3. #include <exception>  
  4. using namespace std;  
  5. void my_unexpected_handler()  
  6. {  
  7.     cout << "in my_terminate" << endl;  
  8. }  
  9. void fun() throw(int)  
  10. {  
  11.     throw exception("exception");  
  12. }  
  13. int main()  
  14. {  
  15.     set_unexpected(my_unexpected_handler);  
  16.       
  17.     fun();  
  18.     return 0;  
  19. }  

 

7. 异常处理最佳实践

1. 在捕获异常时使用引用而不是值类型

2.  异常中如何处理内存申请和释放?

  1. void func()  
  2. {  
  3.     const int ARRAY_SIZE = 10;  
  4.     double* ptr= new double[ARRAY_SIZE];  
  5.     try  
  6.     {  
  7.         throw "exception";  
  8.     }  
  9.     catch(const char* e)  
  10.     {  
  11.         delete [] ptr;  
  12.     }  
  13.     // 做一些事情  
  14.     delete[] ptr;  
  15. }  

 

posted @   qiang.xu  阅读(1018)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示