yo!这里是异常相关介绍

news2024/11/28 10:58:02

目录

前言

异常的概念

异常的抛出与捕获

捕获过程

重新抛出

规范

异常体系

自定义

标准库

异常的优缺点

后记


前言

        对于程序运行时发生的错误,比如内存错误、除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.coloradmin.cn/o/1256843.html

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

相关文章

Redis 事件轮询

1 Redis 为什么快 数据存在内存中, 直接操作内存中的数据单线程处理业务请求避免了多线的上下文切换, 锁竞争等弊端使用 IO 多路复用支撑更高的网络请求使用事件驱动模型, 通过事件通知模式, 减少不必要的等待… 这些都是 Redis 快的原因。 但是这些到了代码层面是如何实现的呢…

P18 C++ 继承

目录 前言 01 不使用继承会让你多打很多无用的代码 02 继承 最后的话 前言 本期我们学习 C 面向对象编程中的继承。 面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类&#xff0c;这使得创建和维护一个应用程序变得更容易。这样做&#…

【云平台】STM32微信小程序阿里云平台汇总——持续更新

【云平台】STM32微信小程序阿里云平台汇总——持续更新 文章目录 前言总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 【云平台】STM32微信小程序阿里云平台学习板 【云平台】小白从零开始&#xff1a;小程序阿里云平台控制STM32&#xff08…

Centos 7.9 Install Docker Insecure Registry

文章目录 1. 镜像存储规划2. 安装定制 docker3. 部署 registry4. 验证镜像仓库 1. 镜像存储规划 linux LVM /dev/sdb mount dir /data【linux LVM 磁盘挂载目录】 创建两个目录 一个 docker 数据存储目录 &#xff1a;/data/docker&#xff0c;默认一般为linux为 /var/lib/d…

Java游戏制作——王者荣耀

一.准备工作 首先创建一个新的Java项目命名为“王者荣耀”&#xff0c;并在src下创建两个包分别命名为“com.sxt"、”com.stx.beast",在相应的包中创建所需的类。 创建一个名为“img”的文件夹来储存所需的图片素材。 二.代码呈现 package com.sxt;import javax.sw…

B树你需要了解一下

介绍B树的度数主要特点应用场景时间复杂度代码示例拓展 介绍 B树&#xff08;B-tree&#xff09;是一种自平衡的树&#xff0c;能够保持数据有序&#xff0c;常被用于数据库和文件系统的实现。 B树可以看作是一般化的二叉查找树&#xff0c;它允许拥有多于2个子节点。与自平衡…

大数据Doris(二十九):数据导入(Insert Into)

文章目录 数据导入(Insert Into) 一、​​​​​​​创建导入

Echarts 最简单创建柱状图

设置容器 <div ref"myChart" style"width: 500px; height: 500px;"> </div>mounted() {//document渲染完成this.draw()}draw() {const myChart this.$echarts.init(this.$refs.myChart)//初始化对象myChart.setOption({ //参数配置项title: …

OSG编程指南<十一>:OSG几何体操作及三维地形创建

1、简化几何体 在 OSG 中&#xff0c;场景都是由基本的绘图基元构成的&#xff0c;基本的绘图基元构成简单的几何体&#xff0c;简单的几何体构成复杂的几何体&#xff0c;复杂的几何体最终构造成复杂的场景。当多个几何体组合时&#xff0c;可能 存在多种降低场景渲染效率的原…

【双指针】三数之和

三数之和 在做这道题之前&#xff0c;建议建议先将两数之和做完再做&#xff0c;提升更大~ 文章目录 三数之和题目描述算法原理解法一解法二思路如下&#xff1a;处理细节问题&#xff1a; 代码编写Java代码编写C代码编写 15. 三数之和 - 力扣&#xff08;LeetCode&#xff0…

62 权限提升-烂土豆dll劫持引号路径服务权限

目录 演示案例:Win2012-烂士豆配合令牌窃取提权-Web权限Win2012-DLL劫持提权应用配合MSF-Web权限Win2012-不安全的服务权限配合MSF-本地权限Win2012-不带引号服务路径配合MSF-Web&#xff0c;本地权限补充说明: dll劫持提权及AlwaysInstallElevated等说明关于Windows相关知识点…

Redis未授权访问-CNVD-2019-21763复现

Redis未授权访问-CNVD-2019-21763复现 利用项目&#xff1a; https://github.com/vulhub/redis-rogue-getshell 解压后先进入到 RedisModulesSDK目录里面的exp目录下&#xff0c;make编译一下才会产生exp.so文件&#xff0c;后面再利用这个exp.so文件进行远程代码执行 需要p…

微机原理_5

一、单项选择题(本大题共15小题,每小题3分,共45分。在每小题给出的四个备选项中,选出一个正确的答案,请将选定的答案填涂在答题纸的相应位置上。) 8086微处理器CLK引脚输入时钟信号是由(提供。 A. 8284 B. 8288 C.8287 D. 8289 2.下面4个寄存器中,不能作为间接寻址的寄存器是(…

hivesql 将json格式字符串转为数组

hivesql 将json格式字符串转为数组 完整过程SQL在文末 json 格式字符串 本案例 json 字符串参考格式&#xff0c;请勿使用本数据 {"data": [{"province": 11,"id_card": "110182198903224674","name": "闾丘饱乾"…

【开源】基于JAVA的高校学院网站

项目编号&#xff1a; S 020 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S020&#xff0c;文末获取源码。} 项目编号&#xff1a;S020&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学院院系模块2.2 竞赛报名模块2.3 教…

人工智能_机器学习051_支持向量机SVM概念介绍_理解support vector machine---人工智能工作笔记0091

在出现深度学习,神经网络算法之前,支持向量机已经可以解决很多问题了,我们自然界中的问题,无非就是可以转换为回归问题和分类问题. 然后从现在开始我们来看支持向量机,首先看一下这几个字 support 是支持 vector是向量的意思,然后 machine指的是机器 那么我们之前用到的模型…

85基于Matlab的交通设施识别

基于Matlab的交通设施识别。 GUI设计图像处理, 基于数字图像处理&#xff0c;设计实现一个自然场景下公路交通限速标志分割和识别的程序。要求系统具有界面&#xff0c;并实现以下功能&#xff1a; 1&#xff09;读入自然场景下包含交通标志的图像&#xff1b; 2&#xff09;对…

Qt TCP网络上位机的设计(通过网络编程与下位机结合)

目录 TCP 协议基础 QTcpServer 和 QAbstractSocket 主要接口函数 TCP 应用程序 1.服务端 2.客户端 上位机通过网络编程与下位机实现通信 TCP 协议基础 传输控制协议&#xff08;TCP&#xff0c;Transmission Control Protocol&#xff09;是一种面向连接的、可靠的、基于…

蓝桥杯-动态规划-子数组问题

目录 一、乘积最大数组 二、乘积为正数的最长子数组长度 三、等差数列划分 四、最长湍流子数组 心得&#xff1a; 最重要的还是状态表示&#xff0c;我们需要根据题的意思&#xff0c;来分析出不同的题&#xff0c;不同的情况&#xff0c;来分析需要多少个状态 一、乘积最…

Node.js与npm的准备与操作

1.下载 Node.js官网&#xff1a;Node.jsNode.js is a JavaScript runtime built on Chromes V8 JavaScript engine.https://nodejs.org/en 打开后的界面如下&#xff1a; LTS&#xff08;Long Term Support&#xff09;&#xff1a;长期支持版&#xff0c;稳定版 Current&am…