【无标题】c++异常机制的一些总结以及思考

news2024/11/27 10:45:09

在谈及c++处理异常机制的方法之前我们不妨来回顾一下c语言是如何应对这块的。

  1. 终止程序,如assert,缺陷:用户难以接受。如发生内存错误,除0错误时就会终止程序。

  2. 返回错误码,缺陷:需要程序员自己去查找对应的错误。如系统的很多库的接口函数都是通

过把错误码放到errno中,表示错误

如果用assert直接终止程序运行未免也太过粗暴,而且如果单单报错误码我们其实很难看出问题在哪里,所以c++11为了对于这块做出更好的处理补充了新的特性。

1.c++异常概念

1.1概念

异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的

直接或间接的调用者处理这个错误

1.2三个基础用法关键词

throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。

catch: 在您想要处理问题的地方,通过异常处理程序捕获异常.catch 关键字用于捕获异

常,可以有多个catch进行捕获。

try: try 块中放置可能抛出异常的代码,try 块中的代码被称为保护代码,它后面通常跟着一个或多个 catch 块。

try
{
  // 保护的标识代码
}catch( ExceptionName e1 )
{
  // catch 块
}catch( ExceptionName e2 )
{
  // catch 块
}catch( ExceptionName eN )
{
  // catch 块
}

2.异常的使用机制

2.1捕获或抛出遵守的一些规则

首先异常是抛出对象或者普通变量而引发的,此对象的类型决定了应该激活哪个catch处理板块的代码,当两个对象类型一致的时候,看throw与哪个catch近就调用哪个catch。

抛出异常对象后,会生成一个异常对象的拷贝,因为抛出的异常对象可能是一个临时对象,所以会生成一个拷贝对象,这个拷贝的临时对象会在被catch以后销毁。

实际中抛出和捕获的匹配原则有个例外,并不都是类型完全匹配,可以抛出的派生类对象,使用基类捕获

2.2异常调用链中函数栈展开的匹配原则

在这里插入图片描述

double Division(int a, int b)
{
    // 当b == 0时抛出异常
 if (b == 0)
   throw "Division by zero condition!";
    else
        return ((double)a / (double)b);
}
void Func()
{
 int len, time;
 cin >> len >> time;
 cout << Division(len, time) << endl;
}
int main()
{
 try {
 Func();
 }
 catch (const char* errmsg) {
 cout << errmsg << endl;
 }
    catch(...){
   cout<<"unkown exception"<<endl;           //我们最后都要加一个catch(...)捕获任意类型的异常,否则当有异常没捕获,程序就会直接终止。
   }
 return 0;
}
2.3异常的重新抛出

有可能单个的catch不能完全处理一个异常,在进行一些校正处理以后,希望再交给更外层的调用链函数来处理,catch则可以通过重新抛出将异常传递给更上层的函数进行处理。

例子:

  double Division(int a, int b)
{
 // 当b == 0时抛出异常
 if (b == 0)
 {
 throw "Division by zero condition!";
 }
 return (double)a / (double)b;
}


  void Func()
{
 // 这里可以看到如果发生除0错误抛出异常,另外下面的array没有得到释放。
 // 所以这里捕获异常后并不处理异常,异常还是交给外面处理,这里捕获了再
 // 重新抛出去。
 int* array = new int[10];
 try {
 int len, time;
 cin >> len >> time;
 cout << Division(len, time) << endl;
 }
 catch (...)
 {
 cout << "delete []" << array << endl;
 delete[] array;
 throw;
 }
 // ...
 cout << "delete []" << array << endl;
 delete[] array;
}

  int main()
{
 try
 {
 Func();
 }
 catch (const char* errmsg)
 {
 cout << errmsg << endl;
 }
 return 0;
}
2.3异常的安全以及规范

构造函数完成对象的构造和初始化最好不要在构造函数中抛出异常,否则可能导致对象不完整或没有完全初始化

析构函数主要完成资源的清理最好不要在析构函数内抛出异常,否则可能导致资源泄漏(内存泄漏、句柄未关闭等)

// 这里表示这个函数会抛出A/B/C/D中的某种类型的异常
void fun() throw(A,B,C,D);
// 这里表示这个函数只会抛出bad_alloc的异常
void* operator new (std::size_t size) throw (std::bad_alloc);
// 这里表示这个函数不会抛出异常
void* operator delete (std::size_t size, void* ptr) throw();
// C++11 中新增的noexcept,表示不会抛异常
thread() noexcept;
thread (thread&& x) noexcept;

3.c++标准库的异常标准体系

其实实际当中个公司都会有一套自己的异常体系,进行规范的异常管理,往往抛出的异常为继承的派生类对象,这样捕获的时候用基类就可以了

而C++ 提供了一系列标准的异常,定义在 中,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:

在这里插入图片描述
在这里插入图片描述

当然因为这套体系设计的不够好所以我们很少会用到它

4.异常的优缺点

4.1优点
  1. 异常对象定义好了,相比错误码的方式可以清晰准确的展示出错误的各种信息,甚至可以包含堆栈调用的信息,这样可以帮助更好的定位程序的bug。

  2. 返回错误码的传统方式有个很大的问题就是,在函数调用链中,深层的函数返回了错误,那么我们得层层返回错误,最外层才能拿到错误,具体看下面的详细解释。

     // 1.下面这段伪代码我们可以看到ConnnectSql中出错了,先返回给ServerStart,ServerStart再返回给main函数,main函数再针对问题处理具体的错误。
      // 2.如果是异常体系,不管是ConnnectSql还是ServerStart及调用函数出错,都不用检查,因为抛出的异常异常会直接跳到main函数中catch捕获的地方,main函数直接处理错误。
      int ConnnectSql()
     {
     // 用户名密码错误
     if (...)
     return 1;
      
          // 权限不足
     if (...)
     return 2;
     }
      
      int ServerStart() {
     if (int ret = ConnnectSql() < 0)
     return ret;
          int fd = socket() 
          if(fd < 0return errno;
     }
      
      int main()
     {
     if(ServerStart()<0)
     ...
      
     return 0;
     }
    
  3. 很多的第三方库都包含异常,比如boost、gtest、gmock等等常用的库,那么我们使用它们也需要使用异常。

  4. 部分函数使用异常更好处理,比如构造函数没有返回值,不方便使用错误码方式处理。比如T& operator这样的函数,如果pos越界了只能使用异常或者终止程序处理,没办法通过返回值表示错误。

4.2缺点
  1. 异常会导致程序的执行流乱跳,并且非常的混乱,并且是运行时出错抛异常就会乱跳。这会导致我们跟踪调试时以及分析程序时,比较困难。

  2. 异常会有一些性能的开销。当然在现代硬件速度很快的情况下,这个影响基本忽略不计。

  3. C++没有垃圾回收机制,资源需要自己管理。有了异常非常容易导致内存泄漏、死锁等异常安全问题。这个需要使用RAII来处理资源的管理问题。学习成本较高。

  4. C++标准库的异常体系定义得不好,导致大家各自定义各自的异常体系,非常的混乱。

  5. 异常尽量规范使用,否则后果不堪设想,随意抛异常,外层捕获的用户苦不堪言。所以异常规范有两点:一、抛出异常类型都继承自一个基类。二、函数是否抛异常、抛什么异常,都使用 func() throw();的方式规范化。

总结:异常总体而言,利大于弊,所以工程中我们还是鼓励使用异常的。另外OO的语言基本都是用异常处理错误,这也可以看出这是大势所趋。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/471251.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深兰科技再获欧洲订单,中国造智能机器人出海“服务”西班牙

近日&#xff0c;经过包含关键技术、场景适配性、任务完成效率、产品操作便捷度等考核标准在内多轮综合对比&#xff0c;深兰科技突出重围&#xff0c;斩获西班牙一笔价值百万的智能室内清洁机器人采购订单。 多重问题显示&#xff0c;欧洲清洁市场亟待科技赋能 在当前的经济形…

VUE初级知识点总结

前言 近几年随着HTML5的普及&#xff0c;原来的jsp逐渐在被淘汰&#xff0c;而vue成了很多前端开发者的心仪的js框架&#xff0c;因为它相对于其他两大框架&#xff08;Angula、React&#xff09;更简单易学&#xff0c;当然了这里的简单易学指的是上手快&#xff0c;在不知道…

7.3 股票分析(project)

目录 第1关&#xff1a;涨幅和成交量 第2关 涨幅与最高价 第3关 跌幅与最低价 本关任务&#xff1a;完成涨幅和成交量股票分析。 相关知识 1.sorted()函数 2.集合运算 sorted()函数 sorted() 函数对所有可迭代的对象进行排序操作。 sorted(iterable, keyNone, reverseFal…

Linxu下性能指标采集工具之nmon工具的使用

前言 近期在测试JefLogTail&#xff0c;由于JefLogTail使用的是轮询的方式来监听文件夹&#xff0c;所以对cpu的消耗可能会高一些&#xff0c;所以在测试的时候着重关注CPU,Linux下查看CPU信息一般采用top命令来实时观察&#xff0c;但是这种对于只是通过观察数据的变化来评估…

跟着我学习 AI丨初识 AI

人工智能&#xff08;AI&#xff09;是一种模拟人类思维和行为的计算机技术&#xff0c;通过学习、推理和自我修正等方式&#xff0c;使机器能够模拟人类智能&#xff0c;并具有一定的自主决策能力。AI 可以被用于解决各种难题&#xff0c;如自动化、机器人、自动驾驶、语音识别…

【LeetCode】53. 最大子数组和

53. 最大子数组和&#xff08;中等&#xff09; 思路 这道题的状态设计和状态转移和 300. 最长递增子序列 类似。但是这里要求的是连续子数组&#xff0c;和子序列不同。 状态定义 首先定义 dp[i]&#xff1a;以 nums[i] 结尾的具有最大和的连续子数组。 状态转移方程 根据…

idea项目打成war包,出现路径问题(已解决)

参考文档&#xff1a; https://www.cnblogs.com/huaixiaonian/p/10521460.html 解释说明&#xff1a; 什么路径问题呢&#xff0c;就比如你们合作开发了一个项目&#xff0c;然后打成了一个war包&#xff0c;然后路径以前的是这种的 http://localhost:8080 就可以直接运行&…

《计算机网络——自顶向下方法》精炼

“An investment in knowledge pays the best interest.” - Benjamin 文章目录 分布式散列表&#xff08;键-值&#xff09;对散列函数逻辑上的实现环形DHT对等方扰动对等方离开对等方加入 UDP套接字编程客户端代码服务器端代码 分布式散列表 分布式散列表是一种数据库。集中…

锁相环的工作原理

锁相环是一个能够比较输入与输出信号相位差的反馈系统,利用外部输入的参考信号控制环路内部的振荡信号的频率和相位,使振荡信号同步至参考信号。 问题:既然是利用外部的参考时钟控制内部的振荡信号频率和相位使内部信号同步至外部参考,那为什么不直接用导线将外部参考信号…

微服务监控系统选型:Zabbix、Open-Falcon、Prometheus

监控系统的 7 大作用 实时采集监控数据&#xff1a;包括硬件、操作系统、中间件、应用程序等各个维度的数据。实时反馈监控状态&#xff1a;通过对采集的数据进行多维度统计和可视化展示&#xff0c;能实时体现监控对象的状态是正常还是异常。预知故障和告警&#xff1a;能够提…

08 【Sass语法介绍-混合指令】

1.前言 混合指令在 Sass 中也是一个比较常用的指令&#xff0c;在前面我们讲解的内容中有编写过混合指令 mixin &#xff0c;本节我们将详细讲解混合指令 mixin 的语法包括定义混合指令和引用混合指令等等&#xff0c;混合指令同样非常好用&#xff0c;我们一起来学习它吧。 …

python 离线安装pyinstaller

Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirrorhttps://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/下载各类anaconda Archived: Python Extension Packages for Windows - Christoph Gohlke (uci.edu)https://www.lfd.uci.edu/~g…

OpenGL(二)—— Hello World

目录 一、前言 二、渲染 三、GLSL 3.1 数据类型 3.2 编程步骤 四、渲染窗口 五、渲染三角形 5.1 顶点输入 5.2 顶点着色器 5.3 片段着色器 5.4 着色器链接 5.5 顶点属性 5.6 VAO管理顶点属性 5.7 画图 六、渲染四边形 6.1 元素缓冲对象EBO 6.2 运行 一、前言 G…

hbuilder打包IOS上线APP流程

iOS 系统打包流程 1. 创建唯一标识符 &#xff08;1&#xff09; 首先&#xff0c;申请苹果开发者账号。没有苹果开发者账号是无法进行 ios 打包上线的。 &#xff08;2&#xff09; 进入链接: https://developer.apple.com 这个网址&#xff0c;点击“account”并输入苹果开…

计算机含金量最高的赛事大全,考研和工作都能加持,这才是该参加的比赛

现在计算机相关的赛事数不胜数&#xff0c;但含金量较高的比赛却只有那么几项&#xff0c;做好了你现场就能找到工作&#xff0c;就算是考研也是益处很大&#xff0c;今天给大家总结出来。 就别再折腾一些费时费力但又不讨好的比赛了。 文章目录 一、ACM国际大学生程序设计竞赛…

【0基础学爬虫】爬虫基础之自动化工具 Playwright 的使用

大数据时代&#xff0c;各行各业对数据采集的需求日益增多&#xff0c;网络爬虫的运用也更为广泛&#xff0c;越来越多的人开始学习网络爬虫这项技术&#xff0c;K哥爬虫此前已经推出不少爬虫进阶、逆向相关文章&#xff0c;为实现从易到难全方位覆盖&#xff0c;特设【0基础学…

autosar软件分层架构组成--汽车电子

介绍 autosar是汽车软件协会制定的一套软件标准 本文章所有图片来源于网络 一、分层架构 分层&#xff1a;3层 1.上层应用层&#xff08;Application Layer&#xff09; 2.中间件RTE(Runtime Environment) 3.下层的基础软件&#xff08;Basic Software&#xff09; 中间件R…

电脑截图快捷键有哪些?5大截图方法总结!(2023版)

案例&#xff1a;电脑截图快捷键 【朋友们&#xff0c;最近我总是需要用到电脑截图&#xff0c;有什么比较好用的电脑截图快捷键可以帮助我提高效率的吗&#xff1f;感谢感谢&#xff01;】 电脑截图是我们日常工作、学习中不可或缺的一项功能。在Windows系统中&#xff0c;快…

python图像处理之形态学梯度、礼帽、黑帽

文章目录 简介实战 简介 腐蚀和膨胀是图像形态学处理的基本运算&#xff0c;这两种运算的复合运算构成了开和闭&#xff0c;而腐蚀、膨胀与原图之间的加减操作&#xff0c;则构成了形态学梯度、礼帽和黑帽计算。 由于这几种函数均基于腐蚀和膨胀&#xff0c;所以其参数均与开…

zynq基于XDMA实现PCIE X8通信方案测速 提供工程源码和QT上位机程序和技术支持

目录 1、前言2、我已有的PCIE方案3、基于zynq架构的PCIE4、总体设计思路和方案5、vivado工程详解6、SDK 工程详解7、驱动安装8、QT上位机软件9、上板调试验证9、福利&#xff1a;工程代码的获取 1、前言 PCIE&#xff08;PCI Express&#xff09;采用了目前业内流行的点对点串…