【C++】异常的使用和细节

news2024/12/24 2:15:33

传统C语言错误异常的方式

C语言一般使用assert来处理错误,assert确实很不错,可以把错误的行数都提示出来,但是,assert有一个致命的缺点,就是触发assert之后就会终止程序,还有一点就是在release环境下,assert是不起作用的。

C++异常处理方式

异常是一种处理错误的方式,当触发了异常的判定条件,就会自动捕获异常信息,但是程序不会终止,会继续运行,就不会导致一个用户触发了异常导致所有用户掉线的情况了。

  • throw:程序出现问题的时候,通过throw去抛出异常的。
  • catch:异常可以通过catch捕获到,throw就是把信息传递给catch了。
  • try:在try代码块中可以放你想捕获异常的模块,try后面一般会跟很多个catch来捕获异常。
try
{
  // 保护的标识代码
}catch( ExceptionName e1 )
{
  // catch 块
}catch( ExceptionName e2 )
{
  // catch 块
}catch( ExceptionName eN )
{
  // catch 块
}

ExceptionName:异常类名字

异常的使用

异常的抛出和匹配原则

  • 异常是通过抛出对象而引发的,匹配就是根据对象类型来匹配。
  • 触发了异常的代码,会从throw开始找最近的catch,然后被捕获。
  • 抛出异常之后,其实是一个即将被销毁的变量,需要生成一份拷贝对象,因为抛出的异常对象是一个临时的对象,出了作用域会被销毁的,被捕获的也是这个拷贝对象。
  • catch(…)可以捕获任意类型的异常,但是没有错误信息。
  • 抛出的异常类型可以是派生类的对象,然后用基类捕获。

#include<iostream>
using namespace std;

double Division(int a, int b)
{
	if (b == 0)
	{
		throw "除0错误!";
	}
	else
	{
		return double(a / b);
	}
}

void Func()
{
	int a,b;
	cin >> a >> b;
	cout << Division(a, b) << endl;
}

int main(void)
{
	try
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (...)
	{
		cout << "未知错误" << endl;
	}

	return 0;
}

异常的重新抛出

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

#include<iostream>
using namespace std;

double Division(int a, int b)
{
	if (b == 0)
	{
		throw "除0错误!";
	}
	else
	{
		return double(a / b);
	}
}

void Func()
{
	int* arr = new int[10];

	int a, b;
	cin >> a >> b;
	cout << Division(a, b) << endl;
	
	cout << "delete[]" << arr << endl;
	delete[]arr;
}

int main(void)
{
	try
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (...)
	{
		cout << "未知错误" << endl;
	}

	return 0;
}

对于上述程序,如果触发了异常,arr的空间不会正确释放,因此会导致内存泄漏,可以如下修改,在**Func()**当中进行二次捕获异常。

#include<iostream>
using namespace std;

double Division(int a, int b)
{
	if (b == 0)
	{
		throw "除0错误!";
	}
	else
	{
		return double(a / b);
	}
}

void Func()
{
	int* arr = new int[10];
	try
	{
		int a, b;
		cin >> a >> b;
		cout << Division(a, b) << endl;
	}
	catch(...){
		cout << "delete[]" << arr << endl;
		delete[]arr;
		throw;
	}
	
	cout << "delete[]" << arr << endl;
	delete[]arr;
}

int main(void)
{
	try
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (...)
	{
		cout << "未知错误" << endl;
	}

	return 0;
}

这样就不会有空指针问题了。

异常安全问题

  • 最好不要再构造函数里面抛异常,可能导致初始化不完全。
  • 最好不要在析构函数内抛异常,可能导致资源清理不完全。

自定义异常体系

实际使用中很多公司都会自定义自己的异常体系进行规范的异常管理,因为一个项目中如果大家 随意抛异常,那么外层的调用者基本就没办法玩了,所以实际中都会定义一套继承的规范体系。 这样大家抛出的都是继承的派生类对象,捕获一个基类就可以了

#include<iostream>
#include<Windows.h>
#include<string>
using namespace std;

double Division(int a, int b)
{
	if (b == 0)
	{
		throw "除0错误!";
	}
	else
	{
		return double(a / b);
	}
}

void Func()
{
	int* arr = new int[10];
	try
	{
		int a, b;
		cin >> a >> b;
		cout << Division(a, b) << endl;
	}
	catch(...){
		cout << "delete[]" << arr << endl;
		delete[]arr;
		throw;
	}
	
	cout << "delete[]" << arr << endl;
	delete[]arr;
}

class Exception
{
public:
	Exception(const string& errmsg, int id)
		:_errmsg(errmsg)
		, _id(id)
	{}

	virtual string what() const
	{
		return _errmsg;
	}

protected:
	string _errmsg;
	int _id;
};

class sqlException :public Exception
{

public:
	sqlException(const string& errmsg, int id, const string& sql)
		:Exception(errmsg, id)
		, _sql(sql)
	{}

	virtual string what() const
	{
		string str = "SqlException:";
		str += _errmsg;
		str += "->";
		str += _sql;
		return str;
	}

private:
	const string _sql;
};

class HttpServerException : public Exception
{
public:
	HttpServerException(const string& errmsg, int id, const string& type)
		:Exception(errmsg, id)
		, _type(type)
	{}
	virtual string what() const
	{
		string str = "HttpServerException:";
		str += _type;
		str += ":";
		str += _errmsg;
		return str;
	}
private:
	const string _type;
};

class CacheException : public Exception
{
public:
	CacheException(const string & errmsg, int id)
		:Exception(errmsg, id)
	{}
	virtual string what() const
	{
		string str = "CacheException:";
		str += _errmsg;
		return str;
	}
};


void SQLMgr()
{
	srand(time(0));
	if (rand() % 7 == 0)
	{
		throw sqlException("权限不足", 100, "select * from name = '张三'");
	}
	//throw "xxxxxx";
}

void CacheMgr()
{
	srand(time(0));
	if (rand() % 5 == 0)
	{
		throw CacheException("权限不足", 100);
	}
	else if (rand() % 6 == 0)
	{
		throw CacheException("数据不存在", 101);
	}
	SQLMgr();
}

void HttpServer()
{
	// ...
	srand(time(0));
	if (rand() % 3 == 0)
	{
		throw HttpServerException("请求资源不存在", 100, "get");
	}
	else if (rand() % 4 == 0)
	{
		throw HttpServerException("权限不足", 101, "post");
	}
	CacheMgr();
}

int main()
{
	while (1)
	{
		try 
		{
			Sleep(500);
			HttpServer();
		}
		catch (const Exception& e) // 这里捕获父类对象就可以
		{
			// 多态
			cout << e.what() << endl;
		}
		catch (...)
		{
			cout << "Unkown Exception" << endl;
		}
	}
	return 0;
}

如果是网络错误,我们可以写成重试3次发送再抛出异常。

void SeedMsg(const string& s)
{
	// 要求出现网络错误重试三次
	srand(time(0));
	if (rand() % 3 == 0)
	{
		throw HttpServerException("网络错误", 500, "get");
	}
	else if (rand() % 4 == 0)
	{
		throw HttpServerException("权限不足", 101, "post");
	}

	cout << "发送成功:" << s << endl;
}

void HttpServer()
{
	// 要求出现网络错误,重试3次
	string str = "今晚一起看电影怎么样?";
	//cin >> str;
	int n = 3;
	while (n--)
	{
		try
		{
			SeedMsg(str);

			// 没有发生异常
			break;
		}
		catch (const Exception& e)
		{
			// 网络错误 且  重试3次内
			if (e.getid() == 500 && n > 0)
			{
				continue;
			}
			else
			{
				throw e; // 重新抛出
			}
		}
	}
}

C++标准库的异常体系

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

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

相关文章

如何通过Pytest的插件,轻松切换自动化测试的环境地址?

前言 前面小编介绍了如何通过Pytest的插件来实现自动化测试的环境的切换&#xff0c;当时使用的方法是通过钩子函数进行获取命令行参数值&#xff0c;然后通过提前配置好的参数进行切换测试环境地址。加我VX&#xff1a;atstudy-js 回复“测试”&#xff0c;进入 自动化测试学…

【CDH集群】无法发出查询:Host Monitor未运行

无法发出查询:Host Monitor未运行 【CDH集群】无法发出查询:Host Monitor未运行同事的解决方案解决方法&#xff1a;删除原uuid重启agent查看新uuid修改scm数据库中HOSTS表中的agent的uuid 【CDH集群】无法发出查询:Host Monitor未运行 起初是impala报错&#xff0c;连接不上&…

武器换弹系统这节课出现的bug,角色不能正确掏枪了,只有换完弹夹以后才能正常掏枪了

UE4系列文章目录 文章目录 UE4系列文章目录前言一、蓝图实现二、错误原因三、修改后的效果 前言 在学习武器换弹系统这节课出现的bug&#xff0c;角色不能正确掏枪了&#xff0c;只有换完弹夹以后才能正常掏枪了&#xff0c;就是添加了换弹之后才影响了持枪功能&#xff0c;在…

Maven的入门级——介绍,安装,导入项目,全网最最详细教程!!,包含可能会包的错误的已经指出来了

目录 一.Maven的基本介绍 二. Maven的使用过程 使用步骤&#xff1a; 三.Maven的安装 3.1 下载 3.2 配置环境步骤 3.3配置settings.xml文件 四.入门案列 4.1 配置Eclipse环境 4.2 介绍Maven项目的结构 4.3 运行测试项目 一.Maven的基本介绍 我们可以知道在程序员做项目的时…

ngrok内网穿透可以实现资源共享吗?快解析更加简洁

随着互联网的高速发展&#xff0c;越来越多的人开始意识到内网穿透技术的重要性。在这一技术中&#xff0c;ngrok已经成为了一个备受关注的工具。然而&#xff0c;很多人对于ngrok是否可以进行资源共享存在疑问。本文将从新的角度出发&#xff0c;深入探讨这个问题。 了解什么…

SAP使用函数NUMBER_GET_NEXT创建流水号

1. 系统中设定流水号&#xff1b;使用T-Code&#xff1a;SNRO来创建一个流 输入Object&#xff1a;ZLC_001&#xff0c;然后单击创建。 然后输入Shorttext, Long text, Number length domain在写程序的时候应该会另外创建&#xff0c;这里测试就使用料号的Domain MATNR来做,其他…

Mahout教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 Mahout 是 Apache Software Foundation&#xff08;ASF&#xff09; 旗下的一个开源项目&#xff0c;提供一些可扩展的机器学习领域经典算法的实现&#xff0c;旨在帮助开发人员更加方便快捷地创建智能应用程序。Mahout包含许多实现&#xff0c;包括聚类、分类、推荐…

利用PHP的特性做免杀Webshell

0x01 前言 最近很多家厂商都陆续开放了自己的Webshell检测引擎&#xff0c;并且公开接口&#xff0c;邀请众安全研究员参加尝试bypass检测引擎&#xff0c;并且给予奖励&#xff0c;我也参加了几场类似的活动&#xff0c;有 ASRC 的 伏魔计划 &#xff0c;也有 TSRC 的 猎刃计…

8月盛夏相约|上海国际智能家居展SSHT 精彩亮点抢先看

上海国际智能家居展览会&#xff08;SSHT&#xff09; 2023年8月29至31日 上海新国际博览中心举行 SSHT 作为国内专业智能家居展会&#xff0c;定位为“智能家居技术的行业平台”&#xff0c;以“技术整合”及“跨界合作”为主轴&#xff0c;旨在呈现不同层面的智能家居技术如…

计算机基础知识一

1、计算机系统组成 1.1 硬件 CPU&#xff1a;中央处理器、计算机核心部件、负责计算任务 内存&#xff1a;记忆功能、存储二进制数&#xff0c;内存是一个字节一个地址。 内存大小换算&#xff1a; 8 bits 1 Byte 1024 Bytes Bytes 1 KB &#xff0c; 1024 KB KB 1 …

妙盈面试(部分)

算法题1&#xff0c;二分查找即可&#xff1a; git rebase算法题2&#xff0c;求二叉树两结点的最小公共祖先 搞笑的是&#xff0c;第2道算法题我刚开始做&#xff0c;黑屏了两秒钟&#xff0c;当时其实腾讯会议软件已经崩溃了&#xff0c;但是我没注意到而是继续做题。等到做…

openGauss学习笔记-36 openGauss 高级数据管理-TRUNCATE TABLE语句

文章目录 openGauss学习笔记-36 openGauss 高级数据管理-TRUNCATE TABLE语句36.1 语法格式36.2 参数说明36.3 示例 openGauss学习笔记-36 openGauss 高级数据管理-TRUNCATE TABLE语句 清理表数据&#xff0c;TRUNCATE TABLE用于删除表的数据&#xff0c;但不删除表结构。也可以…

易大师运势测算网站源码含视频搭建教程

微信/支付宝支付、海外paypal支付、积分支付、VIP免支付&#xff0c;易支付&#xff0c;码支付。 对接真人服务、完善的分销功能、支持设置一二多级分成比例、微信/QQ登陆、注册送积分设置。 推广链接被访问送积分设置&#xff0c;海报推广功能、完善的推广机制&#xff0c;可…

MES系统应该涵盖那些功能

导 读 ( 文/ 1497 ) MES系统是专门面向生产环节的软件系统&#xff0c;用于管理、监控原材料转化为中间产品以及成品的过程。尽管市面上有着不同类别、覆盖不同行业的MES系统&#xff0c;但它们都具有一些基本特征&#xff0c;即包括产品文档管理、物料管理、生产执行管理…

CVE-2021-26411在野样本中利用RPC绕过CFG缓解技术的研究

浏览器渲染进程漏洞利用的一般思路是&#xff1a;在利用漏洞获得用户态任意地址读写权限后&#xff0c;通过篡改DOM、js等对象的虚表函数指针劫持程序执行流&#xff0c;通过ROP链调用VirtualProtect等Win32 API&#xff0c;修改保存shellcode buffer的内存属性为PAGE_EXECUTE_…

将matlab中工作区的数据保存为.mat文件及加载.mat数据

将matlab工作区中的数据保存为.mat文件 如数据a a[1 1 2 3 2 4];一、工作区数据 二、保存为.mat文件 利用save保存数据a到data.mat文件中 save(data.mat,a);三、加载数据 Iload(data.mat)

lc18.四数之和

三数之和的延申&#xff0c;四数之和&#xff1a;两层外层for循环双指针 时间复杂度&#xff1a;O(n3) 空间复杂度&#xff1a;O(1) import org.junit.Test;import java.util.ArrayList; import java.util.Arrays; import java.util.List;public class FourSum {Testpublic v…

Centos7.9安装lrzsz进行文件传输---Linux工作笔记059

这里咱们lrzsz命令,需要用来进行文件传输,因为如果不安装这个命令的话,那么 传输安装包什么的就不方便因为只有少数传输工具,才支持,直接拖拽的.没有的时候就可以用这个工具,用命令来传输 直接就是: sz 文件名 就可以把文件下载下来 rz 选择一个文件, 就可以把文件上传到当…

Spring Cloud构建微服务断路器介绍

什么是断路器 断路器模式源于Martin Fowler的Circuit Breaker一文。“断路器”本身是一种开关装置&#xff0c;用于在电路上保护线路过载&#xff0c;当线路中有电器发生短路时&#xff0c;“断路器”能够及时的切断故障电路&#xff0c;防止发生过载、发热、甚至起火等严重后果…

电脑开机出现Boot Device怎么办?

开机出现Boot Device这个问题很常见&#xff0c;有时还会出现No Boot Device的问题&#xff0c;虽然多了一个单词&#xff0c;但意思是相同的&#xff0c;这些问题说明你的系统盘出现了问题&#xff0c;或者是引导出现了问题。这该如何解决呢&#xff1f; 方法1. 检查主板或硬盘…