C++异常处理须知

C++异常处理 基于著名书籍和自我学习得出的C++异常处理 阅读详情

转自:http://blog.youkuaiyun.com/hikaliv/archive/2009/05/24/4212864.aspx

 

http://blog.youkuaiyun.com/CARL_SEN/archive/2009/05/04/4148426.aspx


第一部分:

1.异常发生时,异常对象会沿函数调用栈的反方向抛出,这个过程常称为栈展开。

2.在栈展开过程中,如果异常对象始终都没遇到可行的catch处理块,系统将调用terminate函数强制终止程序。当然如果连try块都没有,系统将直接调用terminate函数。

3.在栈展开过程中,编译器保证适当的撤销局部对象。每个函数在栈展开退出时,它的局部存储会释放,如果局部对象是类类型,则自动调用对象的析构函数。

4.析构函数应该从不抛出异常,因为析构函数都是自动调用的,不会自动加上try测试块,因此析构函数中异常的抛出将直接导致系统调用terminate强制退出。在实践中,由于析构函数释放资源,不太可能出现异常,此外标准库类型都保证它们的析构函数不会引发异常。

5.如果在构造函数中发生异常,则该对象可能只是部分被构造,即使对象只是部分被构造,也要保证将会适当的撤销已构造的成员。

6.不能不处理异常,异常是足够重要的,使程序不能按正常情况执行的正常事件。不去捕获异常将直接导致程序的强制终止。

7.catch子句接收的异常类型可以是内置类型,也可以是类类型,也就是说我们可以抛出(throw)一个如int的一般类型作为异常对象。

8.如果catch子句只需了解异常的类型,则可以省去形参名,像这样:catch(runtime_error) {cout<<"runtime error"<<endl;}。当然,如果需要详细信息必须用形参名来访问异常对象:catch(runtime_error e) {cout<<e.what()<<endl;}。

9.使用异常处理,我们能将问题的检测和问题的解决分离。程序的一部分检测到的问题可以简单的将其抛出(throw),检测部分可以不必了解问题如何处理;程序的另一部分(指调用可能抛出异常的模块实现具体功能的部分)则可以通过try-catch捕获异常,然后处理,这样把异常的处理留给具体功能实现时不失为一个最佳的选择。

10.异常处理中,检测部分抛出对象的类型决定了哪个处理部分的代码被激活,被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那个。

11.异常对象与catch进行匹配的规则很严格,一般除了以下几种情况外,异常类型必须与catch的说明类型完全匹配:允许非const到const的转换,允许派生类到基类的转换,将数组和函数类型转换为对应的指针。

12.异常类型匹配将选择第一个找到的可以处理该异常的catch,因此catch子句列表中,最特殊的catch必须最先出现。而带有因继承而相关的类型的多个catch子句,必须将派生类的处理代码放在基类类型处理代码之前。

13.throw表达式抛出的异常对象不同于一般的局部对象,局部对象会在局部模块退出时撤销,而异常对象由编译器管理,而且保证驻留在可能被激活的任意catch都可以访问到的空间中。这个由编译器管理的异常对象由throw表达式创建,并被初始化为被抛出表达式的副本,异常对象将传给对应的catch并在完全处理后才撤销。

14.由于异常抛出时都进行了一次副本拷贝,因此异常对象必须是可以复制的。

15.抛出一个表达式时,被抛出对象的静态编译时类型将决定异常对象的类型。

16.抛出指针通常是一个坏主意,因为抛出指针要求在对应处理代码存在的任意地方都存在指针所指向的对象(注意此时throw抛出时复制的是指针本身,不会去复制指针指向的内容);而且如果该指针是指向派生类对象的基类指针,则那个对象将被分割只抛出基类部分(第15条中的静态类型规则)。

17.基类异常对象可以用于捕获派生类的异常对象,因此如果catch子句处理因继承而相关的类型,它就应该将自己的形参定义为引用来激活运行时调用的多态性。

18.catch可以继续将捕获到的异常抛出,它使用不带表达式的throw语句重新将异常抛出,如:throw;。被重新抛出的异常对象是原来的异常对象,与catch的形参无关(如原来抛出的是派生类Deriver,catch形参是基类Base,则重新抛出后的异常类型是Deriver),当然如果catch形参是引用的话,原来的异常对象可能已被catch修改了。

19.可以用catch(...){}来捕获所有的异常,catch(...){}经常与重新抛出表达式结合使用,catch(...)完成可做的所有局部工作,然后重新抛出异常。

20.构造函数包括初始化列表的异常处理:

 

  1. Foo::Foo(int n)   
  2. try:size(n), array(new int[n])   
  3. {   
  4.       //...   
  5. }   
  6. catch(const bad_alloc& e)   
  7. {   
  8.       //...   
  9. }  

 

这里的函数测试块将初始化列表和函数体中的代码都纳入try块中。


第二部分:

1.标准异常类定义在四个头文件中:exception,new,type_info,stdexcept。

2.exception中定义了exception类,new中定义了bad_alloc类,type_info中定义了bad_cast类,stdexcept中定义了runtime_error、logic_error类。

3.runtime_error类(表示运行时才能检测到的异常)包含了overflow_error、underflow_error、range_error几个子类;logic_error类(一般的逻辑异常)包含了domain_error、invalid_argument、out_of_range、length_error几个子类;而所有的这些类都是exception类的子类。

4.exception、bad_alloc、bad_cast类只定义了默认构造函数,无法在创建这些异常的时候提供附加信息。其它异常类则只定义了一个接受字符串的构造函数,字符串初始化式用于为所发生的异常提供更多的信息。

5.所有异常类都有一个what虚函数,它返回一个指向C风格字符串的指针。

6.应用程序可以从exception或者中间基类派生自已的异常类来扩充exception类层次。

7.异常说明跟在函数形参表之后,一个异常说明在关键字throw之后跟着一个由圆括号括住的异常类型表,如:void foo(int) throw(bad_alloc, invalid_argument);。异常列表还可以为空:void foo(int) throw();,表示该函数不抛出任何异常。

8.异常说明有用的一种重要情况是,如果函数可以保证不会抛出异常。确定函数将不抛出任何异常,对函数的使用者和对编译器都是非常有用的。知道函数不抛出异常会简化编写该函数异常安全的代码工作,而编译器则可以执行被抛出异常抑制的代码优化。

9.标准异常类中的析构函数和what虚函数都承诺不抛出异常,如what的完整声明为:virtual const char* what() const throw();。

10.派生类中的虚函数不能抛出基类虚函数中没有声明的新异常,这样在编写代码时才有一个可依赖的事实:基类中的异常列表是虚函数的派生类版本可以抛出的异常列表的超集。

11.上半部分说过,在异常抛出栈展开的时候,编译器会适当撤销函数退出前分配的局部空间,如果局部对象是类类型,则自动调用它的析构函数。但如果在函数内单独地使用new动态的分配了内存,而且在释放资源之前发生了异常,那么栈展开时这个动态空间将不会被释放。而由类类型对象分配的资源不管是静态的还是动态的一般都会适当的被释放,因为栈展开时保证调用它们的析构函数。因此,在可能存在异常的程序以及分配资源的程序最好使用类来管理那些资源,看一个例子:

 

  1. void f()   
  2. {   
  3.     const int N=10;   
  4.     int* p=new int[N];   
  5.     if(...)   
  6.     {   
  7.         throw exception;    
  8.     }   
  9.     delete[] p;   
  10. }  

 

当这个异常发生时,p指向的动态空间将不会被正常撤销。现在我们用类来管理这个资源:

 

  1. template <typename T>   
  2. class Resource   
  3. {   
  4. private:   
  5.     unsigned int size;   
  6.     T* data;   
  7. public:   
  8.     Resource(unsigned int _size=0):size(_size),data(new T[_size])   
  9.     {   
  10.         for(unsigned int i=0; i<size; ++i) data[i]=T();   
  11.     }   
  12.     Resource(const Resource& r):size(r.size),data(new T[r.size])   
  13.     {   
  14.         for(unsigned int i=0; i<size; ++i) data[i]=r.data[i];   
  15.     }   
  16.     Resource& operator=(const Resource& r)   
  17.     {   
  18.         if(&r!=this)   
  19.         {   
  20.             size=r.size;   
  21.             delete[] data;   
  22.             data=new T[size];   
  23.             for(int i=0; i<size; ++i) data[i]=r.data[i];   
  24.         }   
  25.         return *this;   
  26.     }   
  27.     ~Resource() { delete[] data; }   
  28.     T operator[](unsigned int index);   
  29.     const T operator[](unsigned int index) const;   
  30. };   
  31. void f()   
  32. {   
  33.     const int N=10;   
  34.     Resource<int> p(N);   
  35.     if(...)   
  36.     {   
  37.         throw exception;    
  38.     }   
  39. }  

 

这里即使抛出了异常,也会自动调用对象p的析构函数。

12.异常抛出栈展开的时候,编译器对局部类对象析构函数的自动运行导致了一个重要的编程技巧的出现,它使程序更为异常安全的。通过定义一个类来封装资源的分配和释放,可以保证正确的释放资源。这一技术常称为“资源分配即初始化”,简称为RAII。第11条已给出了它的用法。


更多参考:

C++ 类构造函数初始化列表的异常机制 function-try block

续:为何说 C++ 构造函数初始化列表异常机制是必要的

C++ try 块里 new 类对像构造异常时发生“回退”并对资源自动释放

C++ 异常处理 C++ 异常处理 文章目录C++ 异常处理1. 异常关键字2. 异常处理实例3. C++ 标准异常4. 自定义异常5. 被遗弃的标准 1. 异常关键字 异常是程序在 执行期间 产生的问题。C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。 异常提供了一种 转移程序控制权 的方式。 C++ 异常处理涉及到三个关键字:try、catch、throw。 关键字 描述 th... 阅读详情

相关推荐

C++异常处理实现(libstdc++)

为了更好的理解C++中异常处理的实现,本文简单描述了Itanium ABI中异常处理的流程和llvm/libsdc++简要实现。

梦的灰色边沿... 2259

【c++复习笔记】——异常处理机制

​ 💂 个人主页:努力学习的少年 🤟 版权:本文由【努力学习的少年】原创、在优快云首发、需要转载请联系博主 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 ​

sjp11的博客 3528

电机控制必看!SVPWM谐波优化:5段式与7段式全参数对比测试

本文通过实测数据,对比分析了电机控制中5段式与7段式SVPWM控制算法的谐波性能。实验表明,7段式SVPWM在电流波形质量(THD)和低速性能上更优,而5段式SVPWM则在开关损耗和效率方面表现突出。文章为工程师在不同应用场景(如对噪音、效率或动态响应的侧重)下的算法选型提供了清晰的依据和实用的工程指南。

weixin_28331555的博客 179

[C++番外] 第三十三节 抛异常

异常总体而言,利大于弊,所以工程中我们还是鼓励使用异常的。

2301_80017277的博客 1401

国产谷歌地球,地形分析秒杀同款地图软件

咱们做地质、林业、水文、水利、电力、GIS、地图、水保、环境的,需要经常用到各种数据,比如影像、地形、矢量、模型等,但目前80%的规划大数据展示都离不开ArcGIS,令人头大的是很多朋友连ArcGIS软件安装起来都费劲。。。 那不会ArcGIS又装不了Google Earth怎么开展工作? 今天推荐大家一款国产免费专业地图浏览下载测量分析神器—图新地球 图新地球,国产三维gis软件。可以查看高清卫星影像地形以及其他很多常用电子地图,对地图需求的掌握远胜过Google Maps,而且上手比国外软件要简单

GISWorld3D的博客 3687

解决 Clawdbot 对接 Minimax 出现 401 (Token is unusable) 的问题排查与修复

即便确认 API Key 有效且余额充足,该问题仍可能在 Clawdbot 中持续出现,而在其他工具(如 curl 或 Postman)中测试正常。

hampeter的博客 3076

C++抛出异常处理简单介绍

一、原理 try{ //1:抛出异常的代码 //2:代码 }catch(){ //3:代码 //4:抛出异常 }finally{ //5:代码 } //6:代码 首先要明确的一点是:不管try是否抛出异常,finally语句块都会执行。 整个try,catch,finally执行有以下几种情况: 1:try语句块没有抛出异常。如果是这种情况,程序

ihungry的专栏 597

私募pp网-私募排行js逆向

在数据采集的学习过程当中,发现了一个有意思的网站,所以记录一下,仅供学习交流,用于其他用途与作者无关。目标:私募基金当中的列表页数据。

zzp28218的博客 1897

【c++】异常处理

当程序在运行过程中出现问题,没有达到理想效果时,异常可以帮助我们对这些问题进行通信并做出相应的处理,将问题的检测与解决问题的过程分离开,更好地应对大型项目可能出现的各种情况。相比于C语言处理错误的方式--返回错误码,我们在c++中,遇到异常时可以抛出一个对象,该对象所携带的错误信息可以更加全面。本篇文章,我们主要学习了异常的使用方法及其处理机制。相比c语言错误码的方式,c++的异常可以更加全面地处理程序出现的问题。但异常也有些缺点,例如造成程序执行混乱,内存泄漏等等。

2301_80955819的博客 1658

LoRa双端通信稳定性核心:同步字配置与LLCC68工程实践

LoRa是一种基于扩频调制的远距离低功耗无线通信技术,其物理层鲁棒性依赖于发射端与接收端在频率、带宽、扩频因子及同步字等关键参数上的严格一致。同步字作为LoRa帧结构中位于前导码之后的2字节标识字段,承担着物理层帧过滤与网络隔离的核心作用,直接影响通信成功率与抗干扰能力。在实际嵌入式开发中,尤其采用LLCC68等专用射频芯片时,同步字配置错误或双端不一致是导致‘能发不能收’‘间歇性丢包’等典型问题的首要原因。本文面向STM32等Cortex-M平台开发者,结合硬件一致性约束、驱动移植方法论与寄存器级调试手段

weixin_36019375的博客 131

【CANoe】CAPL_ECU上电后首帧报文发出时间检测

【CANoe】CAPL_ECU上电后首帧报文发出时间检测,通过CANoe I/O口检测电压实现

星Yeah 的博客 2511

PHP-CPP异常处理机制:从C++到PHP的错误传递终极指南

PHP-CPP是一个强大的C++库,它允许开发者创建高效的PHP扩展,将C++的性能优势与PHP的灵活性完美结合。在开发PHP扩展时,异常处理是确保代码健壮性和可靠性的关键环节。本文将深入探讨PHP-CPP的异常处理机制,从C++异常的抛出到PHP错误的传递,为你提供一套完整的错误处理解决方案。 ## 🧩 PHP-CPP异常体系核心组件 PHP-CPP提供了一套完善的异常处理体系,主要包含以

gitblog_00507的博客 539

【气候模式降尺度】分位数增量映射(QDM)原理及MATLAB代码实现

简介QDM原理及其MATLAB代码实现

WW、forever的博客 5864

Cpp_异常处理

一、为什么需要异常?1.程序不可能不出错2.传统的错误处理机制存在缺陷 1)通过返回值表示错误 缺点:错误处理流程比较复杂,逐层判断,代码臃肿。 优点:函数调用路径中所有的局部对象(栈对象)都能被右花括号正确地析构,不会内存泄漏。 2)通过远程跳转处理错误优点:不需要逐层判断,一步到位处理错误,代码精炼。 缺点:函数调用路径中的局部对象失去被析构机会,形成内存泄漏。3.C++的异常结合两种

Jerry的专栏 2502

Superpowers与 OpenSpec、Spec Kit 对比

按照官方仓库定义,Superpowers 是一套构建在 composable skills 之上的完整软件开发工作流。它不是单纯的 prompt 集合,而是把一系列工程动作做成默认流程。一个需要明确的点:Superpowers 并不只偏 Claude Code,根据。

人不风流枉少年 1814

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Cpp(六) 异常处理Exception

文章目录C++ 异常处理#1 环境#2 开始#2.1 格式#2.2 异常类型#2.3 自定义异常 C++ 异常处理 #1 环境 C++14 CMake 3.17 macOS 10.15.5 Clion #2 开始 #2.1 格式 格式: try{ // 抛异常 throw ExceptionType("xxx"); }catch( ExceptionType1 e1 ){ // ExceptionType1异常 // 异常处理 }catch( ExceptionType2 e2

Auto 1623

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

C++ 异常处理总结

一、 参考文献: 【1】C++异常处理:https://www.runoob.com/cplusplus/cpp-exceptions-handling.html

灰太狼的小秘密 3701

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

C++的异常处理

一、什么是异常处理        一句话:异常处理就是处理程序中的错误。二、为什么需要异常处理,以及异常处理的基本思想        C++之父Bjarne Stroustrup在《The C++ Programming Language》中讲到:一个库的作者可以检测出发生了运行时错误,但一般不知道怎样去处理它们(因为和用户具体的应用有关);另一方面,库的用户知道怎样处理这些错误,但却

大黑暗天 的专栏 2万+

【C++】异常处理

关于C++中的异常

2303_80828380的博客 1546

C++中的异常处理方式

在C++中,异常是程序运行期间发生的意外或错误情况。这些情况可能会导致程序无法继续正常执行,但又不能在当前的代码位置立即处理。异常提供了一种机制,使得在错误发生时可以将控制权从当前代码的执行位置转移到异常处理代码的位置,从而进行适当的处理。

decade777555的博客 1854

【C++】异常处理机制

C++异常机制通过throw和try-catch实现错误处理,比C语言错误码提供更丰富的错误信息。当异常抛出时,系统执行栈展开,沿调用链查找匹配的catch块。异常匹配支持派生类到基类的转换,便于设计异常继承体系。异常安全至关重要,需防范资源泄漏。C++11用noexcept取代C++98的异常规范,标准库提供以exception为基类的异常体系。

月夜的风吹雨的博客 1268
上一篇: C++异常处理机制核心观点
下一篇: 为什么最好在c++中使用异常
UU_Yang
博客等级 码龄23年 926粉丝 213原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值