c++学习:异常处理机制

c语言的错误处理方式

  1. 返回值
    return 0;
  2. 全局错误标志
    int test()
    {int fd = open ("1.txt",O_RDONLY);if(fd == -1){//open打开文件错误会返回错误码 errnoperror()://或者用strerror可以打印出错误return -1;}return 0;
    }

缺点

  1. 当函数有多级嵌套的时候,要一层一层的进行返回值判断才能知道哪里错误
  2. 错误码不好设置

 c++异常

异常处理的核心思想是,把功能模块代码与系统中可能出现错误的处理代码分离开来,以此来达到使我们的代码组织起来更美观、逻辑上更清晰,并且同时从根本上来提高我们软件系统长时间稳定运行的可靠性。

异常,即exception,是C++中的基本概念之一,在某段程序发生无法继续正常执行的情况时,C++允许程序进行所谓抛出异常(有时也被称为吐出异常)的行为,这些被抛出的异常,会自动地从触发点开始向外传播,直到被捕获(有时也被称为吞下异常)或者程序终止。

抛出异常 throw

int test01()
{int fd = open("1.txt",O_RDONLY);if(fd == -1){//抛出异常 ---字符串对象异常throw "open error";}return 0;
}

捕获异常 try

    try {//可能发生异常的代码块  函数test01();} catch (const char*str) //捕获字符串异常{cout<<"str:"<<str<<endl;}catch (int a) //捕获整型异常{cout<<"a:"<<a<<endl;}catch(...) //捕捉其他异常{cout<<"other"<<endl;}

实例  从键盘输入两个整数(a b),进行相除,输出结果,b等于0抛出异常重新输入

#include <iostream>using namespace std;int main()
{while (1) {cout<<"input two int:";int a,b;try {//有抛出异常的代码块cin>>a>>b;if(b == 0)throw 0;} catch (int ra) {//捕捉到异常之后,对异常的处理cout<<"b != 0"<<endl;//重新执行上面代码块continue;}cout<<"result:"<<a/b<<endl;}return 0;
}

异常类型

抛出异常的时候可以抛出不同的类型异常,有些时候需要抛出很多类型的异常,捕捉的时候就要步骤很多类型异常,很不方便,可以自定义异常体系

自定义异常体系

简单来说就是定义一个异常基类,每当遇到异常就抛出一个异常基类的派生类,捕获的时候就捕获异常基类就可以了

异常基类

//异常基类
class Exception
{
public:Exception(const char*str = nullptr,int id = 0):_errmsg(str),_id(id){}virtual void what() const = 0; //纯虚函数protected:string _errmsg;//错误信息int _id;//错误码
};

如果数据库异常就定义一个数据库异常派生类

//数据库异常
class SqlException:public Exception
{
public:SqlException(const char*str = nullptr,int id = 1):Exception(str,id){}virtual void what() const{cout<<"error msg:"<<_errmsg<<endl;cout<<"error id:"<<_id<<endl;}
};

如果网络异常就定义一个网络异常派生类

class SocketException:public Exception
{
public:SocketException(const char*str = nullptr,int id = 2):Exception(str,id){}virtual void what() const{cout<<"error msg:"<<_errmsg<<endl;cout<<"error id:"<<_id<<endl;}
};

在test函数里遇到了网络和数据库异常,抛出数据库和网络异常

void test()
{//当使用数据库的过程中,发生了一个非正常情况,可以直接抛出一个数据库异常//throw SqlException("sql error");//当使用网络接口的过程中,可能会发生非正常的情况,比如说无法发送数据,或者接收数据不对throw  SocketException("recv data error");
}int main()
{try {test();} catch (Exception &ra) { //用基类类型来捕获ra.what();}return 0;
}

 c++标准库异常体系

c++已经提供了标准的异常类

头文件

#include<exception>

根据标准异常基类生成的派生类

std::exception - cppreference.comicon-default.png?t=N7T8https://zh.cppreference.com/w/cpp/error/exception

异常安全问题

  • 由于抛异常只要找到匹配的catch就直接跳到catch块执行,没有找到对应catch的函数就不会继续执行。这样导致函数的执行流回很乱。可能会导致一些问题。
  • 构造函数完成对象的构造和初始化,最好不要再构造函数中抛出异常,否则可能导致对象不完整或者没有完全初始化析构函数主要完成资源的清理,最好不要在析构函数中抛异常,否则可能导致内存泄漏。
  • C++异常经常会导致资源泄漏问题。比如: 在new和delete中抛出异常,导致new出来的资源没有释放,导致内存泄漏。在Iock和unlock中抛出异常,导致锁没有释放,导致死锁。
  • 有两种解决办法:
    • 将异常捕获,释放资源后,将锁重新抛出。
    • 使用RAI的思想解决。定义一个类封装,管理资源。当要使用时实例化一个类对象,将资源传入,当退出函数,调用对象析构函数,释放资源了

异常规范说明

  • 异常规格说明,是使函数调用者知道函数可能会抛出哪些异常。可以在函数后面接throw(异常类型),列出这个函数可能抛出的所有异常类型。
  • 在函数后面加throw()或者noexcept表示不抛异常
  • 若没有接口声明表示,此函数可能会抛出任意类型的异常

用法1    如何抛出标准异常

#include <iostream>
#include <exception> //C++标准异常头文件using namespace std;float divider(float a, float b)
{// 抛出标准异常对象if(b == 0)throw invalid_argument("b!=0");return a/b;
}int main()
{try {divider(10,0);} catch (exception &ra) {cout<<"333"<<endl;ra.what();//ra没有作用,可以自己继承然后重写函数}return 0;
}

用法2  如何标准化写抛出标准异常   

#include <iostream>
#include <exception> //C++标准异常头文件using namespace std;//函数的后面 所加的 throw(invalid_argument)就是告诉函数的使用者这个函数可能会抛出这个异常对象
float divider(float a, float b) throw(invalid_argument);int main()
{try {divider(10,0);} catch (exception &ra) {cout<<"333"<<endl;ra.what();}return 0;
}
float divider(float a, float b) throw(invalid_argument)
{// 抛出标准异常对象if(b == 0)throw invalid_argument("b!=0");return a/b;
}

用法3  如何表示函数不会抛出异常  noexcept关键字

#include <iostream>
#include <exception> //C++标准异常头文件using namespace std;//noexcept 关键字 明确表示这个函数 不会抛出任何的异常
void test01() noexcept;
void test02() throw();void test01() noexcept
{}
void test02() throw()
{}

 

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

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

相关文章

Python综合数据分析_RFM用户分组模型

文章目录 1.导入数据2.月度订单数据可视化3.数据清洗4.特征工程5.构建User用户表6.求R值7.求F值8.求M值9.显示R、F、M值的分布情况10.显示手肘图辅助确定K值11.创建和训练模型12.给R值聚类13.给聚类后的层级排序14.继续给F、M值聚类&#xff0c;并排序15.为用户整体分组画像 1.…

BOM简介

1.1 常用的键盘事件 1.1.1 键盘事件 键盘事件触发条件onkeydown按键被按下时触发onkeypress按键被按下时触发onkeyup按键被松开时触发 注意&#xff1a;addEventListener事件不需要加on <script>//1. keydown 按键按下的时候触发,按任意键都触发&#xff0c;也可以识…

大创项目推荐 深度学习实现语义分割算法系统 - 机器视觉

文章目录 1 前言2 概念介绍2.1 什么是图像语义分割 3 条件随机场的深度学习模型3\. 1 多尺度特征融合 4 语义分割开发过程4.1 建立4.2 下载CamVid数据集4.3 加载CamVid图像4.4 加载CamVid像素标签图像 5 PyTorch 实现语义分割5.1 数据集准备5.2 训练基准模型5.3 损失函数5.4 归…

【Kubernetes】如何使用 kubectl 操作 cluster、node、namespace、pod

如何使用 kubectl 操作 cluster、node、namespace、pod 在列出、描述、修改或删除其他命名空间中的对象时&#xff0c;需要给 kubectl 命令传递 --namespace&#xff08;或 -n&#xff09;选项。如果不指定命名空间&#xff0c;kubectl 将在当前上下文中配置的默认命名空间中执…

整理的Binder、DMS、Handler、PMS、WMS等流程图

AMS&#xff1a; Binder&#xff1a; Handler&#xff1a; PMS&#xff1a; starActivity&#xff1a; WMS&#xff1a; 系统启动&#xff1a;

1884_emacs ivy minibuffer中上下行导航快捷键修改

全部学习汇总&#xff1a; GitHub - GreyZhang/editors_skills: Summary for some common editor skills I used. 我自己凑了一组emacs的配置使用了很长一段时间&#xff0c;很大程度上的功能在模仿spacemacs&#xff0c;但是我的配置更加轻量化&#xff0c;因此在使用的时候延…

设备树在开发板的系统中的体现

一. 简介 设备树文件中的设备节点&#xff0c;可以在开发板系统中看到。 也就说&#xff0c;开发板加载设备树文件&#xff0c;Linux内核启动系统以后&#xff0c;可以在根文件系统里看到设备树的节点信息。在/proc/device-tree/目录下存放着设备树信息。 二. 设备树在开发板…

数据结构单链表定义及例题(上)

本文简要的介绍了单链表的定义,以及单链表的头插法和尾插法的实现 文章目录 一、单链表数据结构的定义 二、头插法建立单链表(带头节点) 三、尾插法建立单链表(带头节点) 四、打印单链表 五、测试及全部代码 总结 前言 单链表是学习,以及考研无论是408还是自命题都是很重…

序列模型(4)—— Scaling Laws

本文介绍 LLM 训练过程中重要的 Scaling Laws&#xff0c;这是一个经验规律&#xff0c;指出了固定训练成本&#xff08;总计算量FLOPs&#xff09; C C C 时&#xff0c;如何调配模型规模&#xff08;参数量&#xff09; N N N 和训练 Token 数据量 D D D&#xff0c;才能实现…

Spring中Bean的生命周期

第一、Bean的生命周期 Spring中Bean的生命周期就是Bean在Spring中从创建到销毁的整个过程&#xff0c;主要分为以下5个部分&#xff1a; 1.实例化&#xff1a; 给Bean分配内存空间&#xff08;对应JVM中的“加载”&#xff0c;这里只是分配了内存&#xff09;&#xff1b; 2.设…

ffmpeg[学习(四)](代码实现) 实现音频数据解码并且用SDL播放

0、作者杂谈 CSDN大多数都是落后的&#xff0c;要么是到处复制粘贴的&#xff0c;对于初学者我来说困惑了很久&#xff0c;大多数CSDN文章都是使用旧的API &#xff0c;已经被否决了&#xff0c;于是我读一些官方文档&#xff0c;和一些开源项目音视频的输出过程&#xff0c;写…

开源的RNA-Seq分析软件Trinity的详细介绍和使用方法

介绍 GitHub - trinityrnaseq/trinityrnaseq: Trinity RNA-Seq de novo transcriptome assembly Trinity是一种开源的RNA-Seq分析软件&#xff0c;用于转录组的de novo组装。转录组de novo组装是通过将RNA-Seq数据中的短序列片段&#xff08;reads&#xff09;重新组装成完整的…

模型容器与AlexNet构建

一、模型容器——Containers nn.Sequential 是 nn.module的容器&#xff0c;用于按顺序包装一组网络层 Sequential 容器 nn.Sequential 是 nn.module的容器&#xff0c;用于按顺序包装一组网络层 • 顺序性&#xff1a;各网络层之间严格按照顺序构建 • 自带forward()&#xf…

x-cmd pkg | grex - 用于生成正则表达的命令行工具

目录 简介首次用户生成的正则表达式与 perl 和 rust 兼容支持 Unicode 符号友好的用户体验进一步阅读 简介 grex 是一个旨在简化创作正则表达式的复杂且繁琐任务的库和命令行程序。这个项目最初是 Devon Govett 编写的 JavaScript 工具 regexgen 的 Rust 移植。但 regexgen 在…

AArch64 Exception Model学习

提示 该博客主要为个人学习&#xff0c;通过阅读官网手册整理而来&#xff08;个人觉得阅读官网的英文文档非常有助于理解各个IP特性&#xff09;。若有不对之处请参考参考文档&#xff0c;以官网文档为准。 1 Privilege and Exception Levels 1.1 为什么要划分权限&#xf…

MySQL基础笔记(3)DML数据操作语句

顾名思义&#xff0c;全称是数据操作语言&#xff0c;用来对数据库中表的数据记录进行增删改操作~ 目录 一.添加数据 1.给指定字段添加数据 2.给全部字段添加数据 3.批量添加数据 二.修改数据 三.删除数据 一.添加数据 1.给指定字段添加数据 insert into 表名 (字段名…

java数据结构与算法刷题-----LeetCode343. 整数拆分(TODO)

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难&#xff0c;但它就是固定套路而已。其实动态规划只…

jenkins构建git项目timeout

问题点&#xff1a; Started by user unknown or anonymous Running as SYSTEM Building in workspace /var/jenkins_home/workspace/test-one using credential f28d956-8ee1-4f20-a32b-06879b487c70 Cloning the remote Git repository Cloning repository http://git.cc.co…

Flink CDC使用

Flink 环境准备 Flink 版本对应的CDC版本 两个jar包上传到flink bin目录下 flink-sql-connector-mysql-cdc mysql-connector-java 重启Flink集群

stm32的FMC数据访问与突发模式

数据访问 配置外部存储器的宽度为 16 位&#xff0c; FMC 将使用内部的 ADDR[25:1]地址来作为对外部存储器的寻址地址 FMC_A[24:0]&#xff0c;这段描述是在解释在STM32的FMC&#xff08;Flexible Memory Controller&#xff09;中&#xff0c;如何配置外部存储器的宽度为16位…