yo!这里是异常相关介绍

目录

前言

异常的概念

异常的抛出与捕获

捕获过程

重新抛出

规范

异常体系

自定义

标准库

异常的优缺点

后记


前言

        对于程序运行时发生的错误,比如内存错误、除0错误等类型,你会如何处理?是使用assert终止程序或是使用exit返回错误码等等,这些都是C语言阶段使用的处理错误的方法了。c++提出了一种处理错误的方式叫做异常,通过抛出和捕获异常来处理一个错误,涉及到的知识点不是很多,主要包括抛出与捕获原则、异常体系及优缺点,下面我们一一说明。

异常的概念

        异常(Exception)是程序在运行过程中发生异常情况时的一种处理机制,能够在异常发生时跳出当前的程序流程,转而执行异常处理代码,从而保证程序的稳定性和安全性。在C++中,异常通常由程序运行时检测到,比如空指针异常、除零异常、数组越界异常、文件读取异常等等。当程序检测到异常时,可使用try-catch语句来捕获并处理异常。语法如下:

try {// 可能会发生异常的代码块
}
catch (ExceptionType& e1) {// e1类型异常处理代码
}
catch (ExceptionType& e2) {// e2类型异常处理代码
}
catch (ExceptionType& e3) {// e3类型异常处理代码
}

        其中,try块中的代码可能会抛出异常,使用关键字throw抛出异常,然后catch块则会捕获并处理异常。ExceptionType代表抛出的异常类型,&e则是指向异常对象的引用。在catch块中,可以根据具体情况编写处理异常的代码,如输出错误信息、修复异常问题等。

异常的抛出与捕获

  • 捕获过程

1.如果某一个栈帧中throw了一个异常,则看这个异常在此栈帧中有无在一个try块中,如果有,则在此try块下面查找类型匹配的catch语句再进入此atch块进行处理异常;

2.如果没有,则退出此栈帧回到上一个栈帧看这个异常有无在一个try块中;

3.如果直到main函数的栈帧中都没有在一个try块中,则程序会被中止,不过正常情况下知道会抛异常,我们会将此代码放入try块进行检查,而且会在最后加一个catch(...)捕获任意类型的异常,目的就是无论什么异常都捕获,不让程序中止;

4.过程中异常被某个catch块捕获并处理以后,会跳过其他catch块继续执行后面的语句。

注意:

        ①异常是通过抛出对象而引发的,该对象的类型决定了应该激活哪个catch的处理代码

        ②选中的catch块是调用链中与该对象类型匹配且离抛出异常位置最近的那一个,其中调用链是抛异常所在栈帧回溯到try块所在栈帧的所经过的所有栈帧组合;

        ③catch(...)可以捕获任意类型的异常。

eg:

         main()中执行到func函数,进入func函数中执行Div函数,Div函数中设置如果除数是0就抛异常(抛一个字符串),在调用链(Div->func->main)中寻找类型匹配的catch块并处理异常,这里是打印抛出的字符串以提醒用户。

int Div(int x, int y)
{if (y == 0)throw "除0异常";return x / y;
}void func()
{int a = 1;int b = 0;int c = Div(a,b);
}int main()
{try{func();}catch (const char* errmsg){cout << errmsg << endl;}catch (...){cout << "error unknown" << endl;}return 0;
}

 运行:

  • 重新抛出

        如果说一个异常在一个catch块中处理的不充分,需要到调用链的下一个栈帧中继续处理,或者当前栈帧还有任务没有完成就被跨过去了,该怎么办呢?语法支持重新抛出,当在一个catch块中处理了以后,可以重新抛出此异常到调用链的下一个try块寻找匹配的catch块继续处理。比如说,在上面的例子中,func函数的开始去new了一块资源,在函数最后需要释放,但中间调用了Div函数导致抛出异常直接到了main函数那里,导致new的资源无法释放造成内存泄漏,这时我们可以在func函数中放一个try块拦截一下将资源释放了,再重新抛出异常到main函数中继续处理,具体看如下代码块:

int Div(int x, int y)
{if (y == 0)throw "除0异常";return x / y;
}void func()
{int* arr = new int[5];cout << "new int[5]" << endl;try{int a = 1;int b = 0;int c = Div(a, b);}catch (...){delete[] arr;cout << "delete[]" << endl;throw;   //重新抛出}
}int main()
{try{func();}catch (const char* errmsg){cout << errmsg << endl;}catch (...){cout << "error unknown" << endl;}return 0;
}

运行:

  • 规范

1.在一个函数名后面加上一个throw(类型),括号中填入函数中可能抛出的所有异常类型,目的在于让函数使用者知道并在合适的地方捕获对应异常,若没有填入类型说明没有异常,若无throw(),说明此函数可能抛任何类型的异常。

eg:

void fun() throw(int,string,Date)   //这个函数可能会会抛出int\string\Date这三种类型的异常

2.关键字noexcept

        noexcept表示一个函数不会抛出任何异常。当使用noexcept关键字声明一个函数时,编译器会优化代码,因为它知道这个函数不会抛出异常。noexcept关键字有两种形式:noexcept和noexcept(expression)。noexcept表示函数不会抛出异常,noexcept(expression)表示函数在表达式为真时不会抛出异常。expression可以是任何表达式,包括函数调用和运算符。

注意:这两种规范只是c++编写人员希望或者说建议的一种规范异常的方法,用户可以选择遵守也可以选择不遵守,对于企业来说,都会一套自己的规范体系,具体还是要看每个企业的情况。

3.建议不要在构造函数、析构函数中抛出异常,否则可能导致对象不完整或没有完全初始化、可能导致资源泄漏等。

异常体系

  • 自定义

        实际上企业都会自定义自己的异常体系进行规范的异常管理,因为一个项目中如果大家 随意抛异常,那么外层的调用者就没办法接收,所以会定义一套继承的规范体系,如此大家抛出的都是继承的派生类对象,外层的调用者只要捕获一个基类就可以了。比如:

eg:

class Exception
{
public:Exception(const string& msg, int id):_msg(msg), _id(id){}virtual const string what() const{return _msg;}int getid() const{return _id;}
protected:string _msg;int _id;
};class HttpServerException : public Exception
{
public:HttpServerException(const string& msg, int id, const string& type):Exception(msg, id), _type(type){}virtual const string what() const{string str = "HttpServerException";str += ":";str += _type;str += ":";str += _msg;return str;}
private:string _type;
};void SeedMgr(const string& msg)
{srand(time(0));if (rand() % 5 == 0){throw HttpServerException("网络错误", 100, "get");}else if (rand() % 6 == 0){throw HttpServerException("http权限不足", 101, "post");}cout << "发送成功" << endl;
}void HttpServer()
{//实现网络请求遇到错误重新发送(三次)string msg = "你在干什么";int n = 3;while (n--){try{SeedMgr(msg);break;}catch(const Exception& e){if (e.getid() == 100 && n > 0){continue;}else{throw e;}}catch (...){cout << "unknown error" << endl;}}
}int main()
{while (1){Sleep(1000);   //睡眠1秒try{HttpServer();}catch (const Exception& e){cout << e.what() << endl;}catch (...){cout << "unknown error" << endl;}}return 0;
}

 运行:

  • 标准库

        C++ 提供了一系列标准的异常,定义在std中,它们是以父子类层次结构组织起来的,如下图所示。

        实际中我们可以去继承exception类实现自己的异常类,但是实际中很多公司像上面一 样自己定义一套异常继承体系,因为C++标准库设计的不够好用。

 说明:

异常的优缺点

优点:

        ①相比错误码的方式可以清晰准确的展示出错误的各种信息,这样可以帮助更好的定位程序的bug;

        ②能够将异常跳到最外层处理,不用层层跳;

        ③很多的的第三方库都包含异常,比如boost、gtest、gmock等;

        ④部分函数使用异常更好处理,比如 T& operator这样的函数,如果pos越界了只能使用异常或者终止程序处理。

缺点:

        ①运行时出错抛异常就会乱跳。这会 导致我们跟踪调试时以及分析程序时,比较困难;

        ②C++没有垃圾回收机制,资源需要自己管理。有了异常非常容易导致内存泄漏、死锁等异常安全问题。

        总之,异常是利大于弊的,大部分语言都是使用异常处理错误。

后记

        对于不同的企业,异常处理的规范都是不同的,但是都大差不差,具体都是定义一个基类,下级抛出的都是继承此基类的派生类对象,在catch块中捕获基类即可,细节还是要等大家到了企业中再具体去了解自己部门的一个规范,但是涉及到的相关关键字的知识点必须完全掌握,这些是基本能力,异常相关介绍并不难,知识点也不多,详细去看一下就能明白,拜拜。


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

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

相关文章

Linux系统---僵尸进程、孤儿进程

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C/C》 键盘敲烂&#xff0c;年薪百万&#xff01; 有了上一篇博客的学习&#xff0c;我们已经简单了解了进程的基础知识&#xff0c;今天我们再来学习两个特殊的进程&#xff0c;僵尸进程和孤儿进程。 …

7000字详解 动态代理(JDK动态代理 CGLIB动态代理)与静态代理

代理模式 1. 代理模式 概念2. 静态代理3. 动态代理3.1.JDK动态代理3.2.CGLIB动态代理3.3. JDK动态代理和CGLIB动态代理区别 4.静态代理和动态代理区别5.篇末 1. 代理模式 概念 代理模式是一种设计模式。 使用代理对象来替代真实对象&#xff0c;用代理对象去访问目标对象。这样…

虚拟化逻辑架构: LBR 网桥基础管理

目录 一、理论 1.Linux Bridge 二、实验 1.LBR 网桥管理 三、问题 1.Linux虚拟交换机如何增删 一、理论 1.Linux Bridge Linux Bridge&#xff08;网桥&#xff09;是用纯软件实现的虚拟交换机&#xff0c;有着和物理交换机相同的功能&#xff0c;例如二层交换&#…

百面深度学习-自然语言处理

自然语言处理 神经机器翻译模型经历了哪些主要的结构变化&#xff1f;分别解决了哪些问题&#xff1f; 神经机器翻译&#xff08;Neural Machine Translation, NMT&#xff09;是一种使用深度学习技术来实现自动翻译的方法。自从提出以来&#xff0c;NMT模型经历了几个重要的…

HTTP协议发展

HTTP 1.0 -> HTTP 1.1 -> HTTP 2.0 -> HTTP 3.0 (QUIC) 每一代HTTP解决了什么问题&#xff1f; 下图说明了主要功能。 HTTP 1.0 于 1996 年最终确定并完整记录。对同一服务器的每个请求都需要单独的 TCP 连接。 HTTP 1.1 于 1997 年发布。TCP 连接可以保持打开状态…

openGauss学习笔记-132 openGauss 数据库运维-查看openGauss状态

文章目录 openGauss学习笔记-132 openGauss 数据库运维-查看openGauss状态132.1 背景信息132.2 前提条件132.3 操作步骤132.4 参数说明132.5 示例 openGauss学习笔记-132 openGauss 数据库运维-查看openGauss状态 132.1 背景信息 openGauss支持查看整个openGauss的状态&#…

如何在Linux系统安装Nginx并启动

Nginx的介绍 Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器。其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力在同类型的网页服务器中表现较好。官网&#xff1a;nginx newsNginx的下载 前往…

docker基础学习笔记

文章目录 Docker简介Linux下安装DockerDocker常用命令Docker网络Docker存储docker-composedockerfile制作镜像私有仓库镜像导入导出参考 Docker简介 定义&#xff1a;Docker是一个开源的应用容器引擎优势&#xff1a; 一键部署&#xff0c;开箱即用&#xff1a;容器使用基于im…

Qt5.15.2静态编译 VS2017 with static OpenSSL

几年前编译过一次Qt静态库:VS2015编译Qt5.7.0生成支持XP的静态库,再次编译,毫无压力。 一.环境 系统:Windows 10 专业版 64位 编译器:visual studio 2017 第三方工具:perl,ruby和python python用最新的3.x.x版本也是可以的 这三个工具都需要添加到环境变量,安装时勾选…

057-第三代软件开发-文件监视器

第三代软件开发-文件监视器 文章目录 第三代软件开发-文件监视器项目介绍文件监视器实现原理关于 QFileSystemWatcher实现代码 关键字&#xff1a; Qt、 Qml、 关键字3、 关键字4、 关键字5 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&…

人工智能时代的内容写作

内容不再只是王道&#xff0c;正如俗话所说&#xff1a;它是一种流动的货币&#xff0c;推动了巨大的在线信息和影响力经济。 每个品牌都是一个故事&#xff0c;通过其服务和商品讲述自己。尽管如此&#xff0c;大多数客户还是会通过您的在线内容最了解您。 但随着我们进入人…

每日一题:LeetCode-LCR 143.子结构判断

每日一题系列&#xff08;day 05&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

汇编:关于栈的知识

1.入栈和出栈指令 2. SS与SP 3. 入栈与出栈 3.1 执行push ax ↑↑ 3.2 执行pop ax ↓↓ 3.3 栈顶超界的问题 4. 寄存器赋值 基于8086CPU编程时&#xff0c;可以将一段内存当作栈来使用。一个栈段最大可以设为64KB&#xff08;0-FFFFH&#xff09;。 1.入栈和出栈指令…

C语言——函数

导读 &#xff1a; 这篇文章主要讲解一下C语言函数的一些基本知识。 前言&#xff1a;函数的概念 C语言中的函数又常常被称为子程序&#xff0c;是用来完成某项特定的工作的一段代码。就像我们生活中的模块化建造技术&#xff0c;类比模块化建房子的过程&#xff1a;整个程序…

高校大学校园后勤移动报修系统 微信小程序uniapp+vue

本文主要是针对线下校园后勤移动报修传统管理方式中管理不便与效率低的缺点&#xff0c;将电子商务和计算机技术结合起来&#xff0c;开发出管理便捷&#xff0c;效率高的基于app的大学校园后勤移动报修app。该系统、操作简单、界面友好、易于管理和维护&#xff1b;而且对后勤…

Python中类的定义和使用细讲

文章目录 前言一、定义类二、创建类的实例三、创建 _ _ init _ _() 方法四、创建类的成员并访问1. 创建实例方法并访问2. 创建数据成员并访问 五、访问限制 前言 在 Python 中&#xff0c;类表示具有相同属性和方法的对象的集合。在使用类时&#xff0c;需要先定义类&#xff0…

Android安卓设置跳转默认应用商店为Google Play 链接跳转到谷歌商店临时解决方法

手机链接默认不跳转 Google Play 因为大部分安卓厂商系统都根据了自己的需求进行了修改,就成为了系统级导流,想要彻底解除可刷写国际版等原生系统即可恢复 解决方法 使用冻结软件(例如 爱玩机手机助手(root)等应用)对 应用商城 进行临时冻结,如需保证正常使用解除冻结状态即可…

清分系统对账

流程1的问题&#xff1a; 1、通道一天的数据会有多少&#xff0c;有二三十万条交易数据吗&#xff1f; 2、如果数据过大都存到一个Map里面去&#xff0c;机器不得挂了 步骤1总结&#xff1a; 1、通过channelNo获取通道T的数据&#xff0c;因为通道是一天一个文件给过来。在转…

首届教师案例教学竞赛一等奖作品上线至和鲸社区,快来学习!

细心的朋友可能已经发现&#xff0c;近期和鲸社区的频道页上线了一个新专区——“优秀参赛作品专区”。 图.和鲸社区频道页 迄今为止&#xff0c;和鲸参与/支持了 500 多场专业数据科学竞赛&#xff0c;包括面向气象、金融、医学、海洋等不同领域的&#xff0c;面向从业者、科学…

.net 8 发布了,试下微软最近强推的MAUI

先看下实现的效果&#xff1a; 下面发下XAML文件&#xff1a; <?xml version"1.0" encoding"utf-8" ?> <ContentPage xmlns"http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x"http://schemas.microsoft.com/winfx/2009/…