C++知识点 -- 异常

news2025/1/8 5:41:01

C++知识点 – 异常

文章目录

  • C++知识点 -- 异常
  • 一、异常概念
  • 二、异常的使用
    • 1.异常的抛出和捕获
    • 2.异常的重新抛出
    • 3.异常安全
    • 4.异常规范
  • 三、自定义异常体系
  • 四、C++标准库的异常体系
  • 五、C++异常的优缺点


一、异常概念

当一个函数发现自己无法处理错误时,就可以抛出异常,让函数的直接或间接调用者处理这个错误;
throw:当函数出现问题时,会抛出一个异常,是通过throw关键字完成的;
try:try代码块中标识将被激活的特定异常;
catch:用于捕获异常;

异常捕获的基本格式:

double Div(int a, int b)
{
	if (b == 0)
	{
		throw "Division by zero condition!";
	}
	else
	{
		return a / b;
	}
}

void test()
{
	int left, right;
	cin >> left >> right;
	cout << Div(left, right) << endl;
}


int main()
{
	try 
	{
		test();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}

	return 0;
}

当b输入0时,会引发除零错误,Div函数抛出异常,main函数的catch会接收到异常;
在这里插入图片描述

二、异常的使用

1.异常的抛出和捕获

(1)异常是通过抛出对象而引发的,该对象的类型决定了应该激活哪个catch的处理代码;
(2)被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个;

在这里插入图片描述

(3)抛出异常对象后,会生成一个异常对象的拷贝,因为抛出异常的对象可能是一个临时对象,所以会生成一个拷贝,这个拷贝的临时对象在被catch后会销毁;(类似于函数的传值返回)
(4)catch(…)可以捕获任意类型的异常,但是不知道异常错误是什么;

int main()
{
	try 
	{
		test();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (const int errid)//异常抛出与捕获的类型一定要匹配,如果catch没有匹配的类型,程序会直接终止
	{
		cout << errid << endl;
	}
	catch (...)//捕获任意类型的异常,防止出现未捕获异常时 ,程序终止
	{
		cout << "未知异常" << endl;
	}

	return 0;
}

(5)实际中抛出和捕获的匹配原则有个例外,可以抛出派生类对象,用基类捕获;

2.异常的重新抛出

double Div(int a, int b)
{
	if (b == 0)
	{
		throw "Division by zero condition!";
	}
	else
	{
		return a / b;
	}
}

void test()
{
	int* array1 = new int[10];
	int* array2 = new int[5];

	int left, right;
	cin >> left >> right;
	try 
	{
		cout << Div(left, right) << endl;
	}
	catch (...)
	{
		throw;//捕获什么抛什么
	}
	cout << "delete[]" << array1 << endl;
	delete[] array1;
	cout << "delete[]" << array1 << endl;
	delete[] array2;
}


int main()
{
	try 
	{
		test();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	return 0;
}

这里可以看到如果发生除0错误抛出异常,另外下面的array没有得到释放。
所以这里捕获异常后并不处理异常,异常还是交给外面处理,这里捕获了再重新抛出去。

可以在异常重新抛出前释放空间:

void test()
{
	int* array1 = new int[10];
	int* array2 = new int[5];

	int left, right;
	cin >> left >> right;
	try 
	{
		cout << Div(left, right) << endl;
	}
	catch (...)
	{
		cout << "delete[]" << array1 << endl;
		delete[] array1;
		cout << "delete[]" << array1 << endl;
		delete[] array2;

		throw;//捕获什么抛什么
	}
}

3.异常安全

(1)最好不要在构造函数中抛异常,否则可能会导致对象不完整或没有完全初始化;
(2)最好不要在析构函数中抛出异常,否则可能导致资源泄露;
(3)c++中经常会在new和delete中间怕抛出异常,导致资源泄露,应使用RAII来解决该问题;

4.异常规范

(1)异常规格说明目的为了让函数使用者知道该函数会抛出那些类型的异常,可以在函数名后面接throw(类型),列出这个函数可能抛出的所有有异常类型;

void fun() throw(int, char*);

(2)函数后面接throw()或noexcept,表示函数不抛异常;

void fun() throw();
void fun() noexcept;//c++11中新增的noexcept表示函数不会抛异常

(3)若无异常接口声明,则此函数可以抛出任意类型的异常;

三、自定义异常体系

// 服务器开发中通常使用的异常继承体系
class Exception
{
public:
	Exception(const string& errmsg, int id)
		:_errmsg(errmsg)
		, _id(id)
	{}

	virtual string what() const
	{
		return _errmsg;
	}

	int getid() const
	{
		return _id;
	}

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;
	}
protected:
	const string _sql;
};

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;
	}

protected:
	// stack<string> _stPath;
};

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;
};


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

	cout << "本次请求成功" << endl;
}

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

	SQLMgr();
}

void SeedMsg(const string& s)
{
	// 要求出现网络错误重试三次
	srand(time(0));
	if (rand() % 3 == 0)
	{
		throw HttpServerException("网络错误", 100, "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() == 100 && n > 0)
			{
				continue;
			}
			else
			{
				throw e; // 重新抛出
			}
		}
	}
}
//在这里接收了异常后,如果不重新抛出,外面就接受不到其他异常了
//如果SeedMsg没有抛异常就break
//如果SeedMsg抛异常就会走到catch,如果是网络错误,continue重试3次,3次后还是错误,就重新抛出异常,外面会接收到网络异常
//如果SeedMsg抛出其他异常,直接抛出,让外面接收

int main()
{
	while (1)
	{
		//this_thread::sleep_for(chrono::seconds(1));
		Sleep(1000);

		try
		{
			HttpServer();
		}
		catch (const Exception& e) // 这里捕获父类对象就可以
		{
			// 多态
			cout << e.what() << endl;
			// 记录日志
		}
		catch (...)
		{
			cout << "Unkown Exception" << endl;
		}
	}

	return 0;
}

所有的子类异常类都继承于父类异常类,这样在捕获时,统一用父类对象捕获,能够触发多态;

四、C++标准库的异常体系

在这里插入图片描述

五、C++异常的优缺点

优点
(1)相比错误码能狗更加清晰地展现出错误信息,能够更好的定位bug;
(2)传统错误码在函数调用链中,深层函数返回了错误,那么我们得层层返回,最外层才能拿到错误,如果是异常体系,我们可以自由设置在哪层接受异常;
(3)很多第三方库都包含异常,所以我么也要使用异常;
(4)部分函数使用异常更好处理,比如构造函数没有返回值,不方便使用错误码处理;

缺点
(1)会导致程序的执行流乱跳;
(2)异常会有一些性能的消耗;
(3)C++没有垃圾回收机制,资源需要自己清理,一般使用RAII;
(4)C++标准库异常体系定义的不好;
(5)尽量规范使用异常,否则后果不堪设想;

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

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

相关文章

Python超矩形

文章目录 距离函数矩形分割 Rectangle是 scipy.spatial中封装的类&#xff0c;其构造函数只需输入最小值和最大值的数组即可&#xff0c;并且可通过内置的 volume方法计算广义的体积。 from scipy.spatial import Rectanglerec Rectangle((0,0), (5,5)) print(rec.maxes) …

java-会话技术

1.1 会话管理概述 1.1.1 什么是会话 这里的会话&#xff0c;指的是web开发中的一次通话过程&#xff0c;当打开浏览器&#xff0c;访问网站地址后&#xff0c;会话开始&#xff0c;当关闭浏览器&#xff08;或者到了过期时间&#xff09;&#xff0c;会话结束。 举个例子&am…

py_rabbitmq

安装 服务端 https://www.jianshu.com/p/2fb6d5ac17b9 客户端 pip install pika文档 https://rabbitmq.com/tutorials/tutorial-one-python.html 简单示例 生产者 import pika import rabbitmq_study.settings as settingscredentials pika.PlainCredentials(settings…

Python每日一练(20230430)

目录 1. 移除元素 &#x1f31f; 2. 删除排序链表中的重复元素 &#x1f31f; 3. 搜索旋转排序数组 II &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1.…

总结836

学习目标&#xff1a; 4月&#xff08;复习完高数18讲内容&#xff0c;背诵21篇短文&#xff0c;熟词僻义300词基础词&#xff09; 学习内容&#xff1a; 暴力英语&#xff1a;背诵《keep your direction》&#xff0c;默写&#xff0c;英语语法 高等数学&#xff1a;刷题&a…

node笔记_安装nvm管理node版本

文章目录 前言下载nvm安装nvmnvm路径node路径查看版本nvm -v查看nvm的node版本列表&#xff08;nvm list available&#xff09;配置nvm的镜像库mirror选择node版本安装 (node install version)使用指定的node版本&#xff08;nvm use&#xff09; node环境变量配置配置NODE_PA…

【打卡】图像检索与匹配4 孪生网络

任务4&#xff1a;孪生网络 孪生网络是一种由两个相同结构的神经网络组成的模型&#xff0c;其目的是将两个输入数据映射到一个共同的向量空间中&#xff0c;并计算它们之间的相似度或距离。它通常用于图像匹配、人脸识别、语义匹配等任务中。 步骤1&#xff1a;构建三元组数…

MIT 6.824 lab4A总结

Background 一个raft集群的性能很明显和raft的数量有关系&#xff0c;更重要的是如果我们多个key放在一个raft集群里&#xff0c;这样的并行性不太好。所以我们可以考虑分片&#xff0c;利用操作潜在的并行性来提升性能。每一个副本组只管理几个分片的put和get&#xff0c;并且…

网络基础设施 拥塞控制

我经常说&#xff0c;传统的 TCP 优化已经到顶&#xff0c;不会有大意义了&#xff0c;这有两方面意思。 一方面&#xff0c;内在的&#xff0c;TCP 的 ACK 时钟带回的信息就那么多&#xff0c;用足了又能怎样。一个学习最差的差生能控制的分数是是 0&#xff5e;100 分的区间…

【Linux】基础IO——文件系统|软硬链接|动静态库

文章目录 一、磁盘1. 物理结构2. 存储结构3. 逻辑抽象结构 二、文件系统1. 文件系统的结构2. 查看文件3. 删除文件 三、软硬链接1. 软链接2. 硬链接3. ACM 时间 四、动静态库1. 动静态库的介绍2. 静态库的制作3. 动态库的制作4. 动态库的加载 一、磁盘 基于上篇博客所写到的文…

从0搭建Vue3组件库(十一): 集成项目的编程规范工具链(ESlint+Prettier+Stylelint)

欲先善其事,必先利其器。一个好的项目是必须要有一个统一的规范,比如代码规范,样式规范以及代码提交规范等。统一的代码规范旨在增强团队开发协作、提高代码质量和打造开发基石,所以每个人必须严格遵守。 本篇文章将引入 ESLintPrettierStylelint 来对代码规范化。 ESlint ES…

【计算机网络】学习笔记:第三章 数据链路层(八千字详细配图)【王道考研】

基于本人观看学习b站王道计算机网络课程所做的笔记&#xff0c;不做任何获利 仅进行交流分享 特此鸣谢王道考研 若有侵权请联系&#xff0c;立删 如果本篇笔记帮助到了你&#xff0c;还请点赞 关注 支持一下 ♡>&#x16966;<)!! 主页专栏有更多&#xff0c;如有疑问欢迎…

redhat 8.7 安装oracle 11g-11.2.0.4

redhat 8.7 安装oracle 11g-11.2.0.4 1、写在前面&#xff1a;这篇文章最后安装失败了。这是一次失败的尝试&#xff0c;仅做记录。结论是RHEL 8不支持Oracle 11g-11.2.0.4 安装&#xff0c;后续再研究怎么跑起来。1、数据库下载和安装文档1.1、查看oracle 11g 适合安装的linux…

阿里云版GPT官宣,我们问了它10个问题

4月7日&#xff0c;阿里云宣布自研大模型“通义千问”&#xff0c;目前已开始邀请用户测试体验。 阿里达摩院在NLP自然语言处理等前沿科研领域早已布局多年&#xff0c;并于2019年启动大模型研发&#xff0c;通义千问便是其最新成果&#xff0c;相当于阿里云版的“ChatGPT”。 …

让GPT成为护理专家 - 护士的工作如此简单

引子    书接上文《GPT接入企微应用 - 让工作快乐起来》&#xff0c;我把GPT接入了企微应用&#xff0c;不少同事都开始尝试起来了。有的浅尝辄止&#xff0c;有的刨根问底&#xff0c;五花八门&#xff0c;无所不有。这里摘抄几份&#xff1a; “帮我写一份表白信&#xff…

【Prompt】7 个向 chatGPT 高效提问的方法

欢迎关注【youcans的 AIGC 学习笔记】原创作品 【Prompt】7 个向 chatGPT 高效提问的方法 0. 向 chatGPT 高效提问的方法1. 提问方法&#xff1a;明确问题2. 提问方法&#xff1a;简洁清晰3. 提问方法&#xff1a;避免歧义4. 提问方法&#xff1a;提供上下文5. 提问方法&#x…

很不错的一篇文章,值得点赞收藏,带你全面了解MySQL性能调优、错误代码总结和全局参数配置(持续更新中ing)

前言 本文主要介绍当前MySQL性能优化原理实战&#xff0c;包括以下方面&#xff1a; 已更新文章目录MySQL遇到的的错误及解决方法全局参数文件配置详解。 后续希望大家提出宝贵的建议。喜欢的话点赞收藏关注走一波。如有错误的地方&#xff0c;请指出&#xff01;&#xff01;&…

C51 - 自写操作系统

最简OS 1> 版本1&#xff1a;任务建立与切换2> 版本2&#xff1a;定时器切换2.1> main.c2.2> task.c2.3> sleep.c 3> 版本3&#xff1a;加时间片轮转 在51单片机上&#xff0c;实现操作系统最简模型&#xff0c; 学习理解操作系统的基本概念&#xff1b; &am…

〖Python网络爬虫实战㉑〗- 数据存储之JSON操作

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付…

912. 排序数组

1.题目&#xff1a; 2.我的代码&#xff1a; C语言&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* sortArray(int* nums, int numsSize, int* returnSize) {//希尔排序int gap numsSize;//多次预排while (gap > 1) {/…