【C++进阶之路】异常篇

news2024/11/28 18:57:27

文章目录

  • 前言
  • 一、异常
    • 1.简单使用
    • 2.注意事项
    • 3.异常体系
      • ①C++标准异常体系
      • ②自定义异常体系
    • 4.总结
      • 优点
      • 缺点

前言

  是否知道C语言独特的错误处理方式——返回错误码,我们可以根据错误码来识别错误信息,比如识别了错误码,我们再用strerror函数把错误码对应的错误信息打印出来,于是便可知道哪错了。那C++是如何处理错误的呢?

一、异常

补充:C语言处理错误还可以用assert,不过在release版本下是不会弹出错误警告的,只会显示退出代码异常,因此assert是强调应该在调试期间,就把错误扼杀在摇篮中。

1.简单使用

  • 先来感受一下异常的使用方式
double Division(int a, int b)
{
	// 当b == 0时抛出异常
	if (b == 0)
		throw "Division by zero condition!";
	else
		return ((double)a / (double)b);
}
void Func()
{
	int len, time;
	cin >> len >> time;
	cout << Division(len, time) << endl;
}
int main()
{
	try
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (...)
	{
		cout << "unkown exception" << endl;
	}

	return 0;
}

调试一下:

在这里插入图片描述

  • 最终运行结果:
    在这里插入图片描述

再来分析一下具体语法:

  • try 大括号里面是可能存在异常的语句或者函数。
  • catch 用于捕获可能存在的异常。
  • throw抛出异常信息,通过catch进行捕获。

  • 细节1:throw会抛给最近的栈帧的catch。
double Division(int a, int b)
{
	// 当b == 0时抛出异常
	if (b == 0)
		throw "Division by zero condition!";
	else
		return ((double)a / (double)b);
}
void Func()
{
	try
	{
		int len, time;
		cin >> len >> time;
		cout << Division(len, time) << endl;
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;//
	}
	catch (...)
	{
		cout << "unkown exception" << endl;
	}

}
int main()
{
	try
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (...)
	{
		cout << "unkown exception" << endl;
	}

	return 0;
}

这里发生异常就会抛给调用Division的函数Func,因为是最近的一层异常。

画张图总结一下:

在这里插入图片描述

  • 细节2:catch的语法逻辑是跟if else if else 的逻辑一样的,是从最上面的catch,依次往下进行执行,如果存在合适的参数就进去,如果不存在就继续往下执行,直到碰到catch(…)——捕获任意类型的异常为止。如果还没有,就看下一层栈帧里面的catch的参数是否有所匹配,如果有就进去,或者再遇到catch(…)为止,如果到最后一层栈帧还没有,那就报错!

  • 细节3:catch(…)——也就是最后一道防线,如果你要再进行throw,一定要判断下一层栈帧中是否也有catch(…)或者是否有参数匹配的。否则还是会报错的。

  • 细节4:捕获异常之后,如果没有再次抛出的动作,那还按照当前栈帧之后的代码进行运行。

try
{
	//要检查的可能会抛异常的语句或者函数。
	//...
}
catch (const exception& e)
{
	cout << e.what() << endl;
}
catch (...)
{
	throw;//这里就是将捕获的异常进行再次抛出。
	cout << "未知异常" << endl;
}
  • 细节5:一次只能throw一次异常。
	// 当b == 0时抛出异常
	if (b == 0)
	{
		throw "Division by zero condition!";
		throw 1;//是不会走这一句代码的!
	}		

总结:

  1. 可以抛任意类型的错误,但一定要能够捕获,不然是会报错的。
  2. 抛出异常是会给最近一层的栈帧进行处理的。
  3. catch的运行逻辑,类似与if else if else ,且走的是匹配的参数。
  4. catch(…)可以接收任意类型的参数,也可以抛给下一层有try catch的栈帧查看是否合适的参数,如果没有抛给下一层,那按照当前栈帧继续往下运行代码。

2.注意事项

  1. 在完成对象的初始化工作时,不要轻易抛出异常,否则可能会导致,对象的初始化工作,没有做完,可能之后使用的是一个不完整的对象。
  2. 在完成对象的资源清理工作时,也不要随意抛出异常,否则可能会导致内存泄漏等问题。

看这样一段代码:

int add(int n1, int n2)
{
	return n1 + n2;
}
void func()
{
	int* n1 = new int(0);
	//当到这里出现异常时,只需抛出错误信息即可。
	int* n2 = new int(0);
	//当到这里出现异常时,我们不仅需要抛出错误信息,还得返回一个n1的指针进行资源的释放。
	cout << add(*n1, *n2) << endl;
	//当这里出现异常时,需要抛出错误信息,还得需要返回两个指针进行释放。
}
int main()
{
	try
	{
		func();
	}
	catch (...)
	{

	}
	return 0;
}
  • 这是一件异常导致的很麻烦的事情,问题就先留到这里,等在智能指针时一并解决。

3.异常体系

①C++标准异常体系

在这里插入图片描述

  • 说明:箭头的指向是父类。

在这里插入图片描述

  • 注:蓝色方框的是常用的异常类型。

总结:

  1. 采用了继承的方式来达到异常的复用。
  2. 这样设计再加上多态可避免屎山代码。
  3. 返回的信息更加的全面而有针对性(通过类进行返回)。

举例:

int main()
{
	try
	{
		//可能存在异常的代码
	}
	catch (const exception& e)
	//这里实现了多态:通过基类的指针和引用
	//来指向子类的对象。
	{
		cout << e.what() << endl;
	}
	//后面无需再列一串的代码进行匹配,只需要最后一道防线即可。
	catch (...)
	{
		cout << "unknown exception" << endl;
	}
	return 0;
}
  • 异常规范
// 这里表示这个函数会抛出A/B/C/D中的某种类型的异常
void fun() throw(A,B,C,D);
// 这里表示这个函数只会抛出bad_alloc的异常
void* operator new (std::size_t size) throw (std::bad_alloc);
// 这里表示这个函数不会抛出异常
void* operator delete (std::size_t size, void* ptr) throw();
// C++11 中新增的noexcept,表示不会抛异常
thread() noexcept;
thread (thread&& x) noexcept;
  • 缺点1:不是强制的,可以不使用,因为兼容C语言,因此无法强制。
  • 缺点2:C++98的throw可能会过于繁琐,如果抛出的异常类型过多,写起来很烦。

②自定义异常体系

  • 在实际应用当中我们也是根据C++标准异常体系来用的,不过库里的显然不符合所有场景的需求,因此我们需要根据实际的需求来自己写一个异常类(符合实际需求的)但都得继承一下exception,方便统一进行捕获。

4.总结

优点

  1. 相比较C语言的返回值和断言的错误,异常能跳过多层栈帧,并且返回的错误信息更加的准确。
  2. 一些常见的库里面也存在异常,因此具有兼容性和移植性。
  3. 模板函数的异常通过返回值是无法处理的,抛异常能更好地解决这类问题。

缺点

  1. 因为可能会跳过多层栈帧,因此可能会打乱执行流,也就是说发生错误了,按照正常逻辑顺序,打的断点可能会直接跳过。
  2. 异常通常是以对象形式进行返回的,可能开销有点大,不过也只是有点而已,CPU很快,影响可以说忽略不计了。
  3. 异常的执行流乱跳,可能会导致内存泄漏的问题,具体样例看上面的代码。解决方法RAII,智能指针部分我们统一解决。
  4. C++的标准异常体系定义的太简陋了,因此会导致各个公司都有一套自己的标准体系。
  5. 尽量按照规范进行抛异常,因为一般异常都是在一个固定的区域进行捕获的,乱抛异常可能会导致无法定位异常的准确位置的问题。不过这个东西,C++并没有强制,不过规范是为了更为安全的使用和书写代码,因此还是按照规范来吧。

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

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

相关文章

信号产生梳状滤波效应的原理和代码演示

声学的梳妆滤波效应&#xff0c;是由于信号沿不同路径传播&#xff0c;时延不同造成的&#xff0c;对吧&#xff1f; 是的&#xff0c;声学的梳妆滤波效应是由于声音信号在传播过程中经历多条不同路径的反射和折射&#xff0c;导致信号到达听者耳朵的时间延迟不同&#xff0c;从…

CentOS7 安装 MongoDB5

MongoDB是一种NoSQL数据库&#xff0c;它存储数据的方式与传统的关系型数据库不同。MongoDB使用文档数据库模型&#xff0c;将数据存储在自包含的、可扩展的BSON文档中。MongoDB具有高可用性、自动分片、动态查询能力、灵活性等优点&#xff0c;适合于许多不同的应用场景。 下…

springboot项目打包 以及打包碰到各种问题

PS:以上资料都来自于网络 1.IDEA 将springboot项目打包 IDEA如何打包springboot成jar包&#xff0c;并运行、停止、重启&#xff0c;本地依赖不能打包怎么办_真是6的不行的博客-CSDN博客 2.[WARNING] Error injecting: org.springframework.boot.maven.RepackageMojo 1.注释…

数学建模—分类模型

本讲将介绍分类模型。对于而分类模型&#xff0c;我们将介绍逻辑回归&#xff08;logistic regression&#xff09;和Fisher线性判别分析两种分类算法&#xff1b;对于多分类模型&#xff0c;我们将简单介绍Spss中的多分类线性判别分析和多分类逻辑回归的操作步骤下。 本题按水…

Appium PO模式UI自动化测试框架——设计与实践

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

数学建模笔记 多元回归分析

本文内容来自数学建模清风老师的课件&#xff0c;是个人学习笔记&#xff0c;不保证完全正确&#xff0c;在此推荐学习清风老师视频讲解&#xff1a;清风建模算法、编程、写作培训https://www.bilibili.com/video/BV1DW411s7wi/?p3&wxfido7omF0atg6R7pnBLLqfBx0B-rjBU 多元…

安装Lombok--Lombok的常用注解说明及使用方法

&#x1f600;前言 本篇博文是关于Lombok的基本介绍和基本使用&#xff0c;希望能够帮助到您&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满…

23款奔驰GLS450时尚型升级原厂香氛负离子系统,清香宜人,久闻不腻

奔驰原厂香氛合理性可通过车内空气调节组件营造芳香四溢的怡人氛围。通过更换手套箱内香氛喷雾发生器所用的香水瓶&#xff0c;可轻松选择其他香氛。香氛的浓度和持续时间可调。淡雅的香氛缓缓喷出&#xff0c;并且在关闭后能够立刻散去。车内气味不会永久改变&#xff0c;香氛…

将大容量机械硬盘克隆到固态硬盘的简单方法!

可以大容量机械硬盘克隆到固态硬盘吗&#xff1f; 随着硬盘使用时间增长&#xff0c;电脑的性能可能会下降。为了追求更快的读写速度&#xff0c;不少用户将目光投向了固态硬盘。 ​众所周知&#xff0c;固态硬盘的读写速度和启动速度比机械硬盘快。用固态硬盘替…

关于笔记本 win11系统出现的白屏闪烁问题

环境 windows 11 21H2 小新16pro笔记本起因 今天早上到公司&#xff0c;打开电脑后&#xff0c;发现电脑在登录后出现白屏闪烁的情况&#xff0c;闪烁是以下两张图反复更换&#xff1a; 看起来像是桌面程序出现问题&#xff0c;背景一会有一会没有的状况&#xff0c;通过Ctrl…

如何系列 如何使用Resilience4j提高应用弹性和容错

文章目录 背景简介Maven重试器注解式编程式配置事件监听指标监控健康检查 速率限制注解式编程式配置事件监听指标监控动态修改配置 断路器注解式配置 舱壁注解式 时间限制器多组件配合使用最佳实践 配置参考&#xff1a; 背景 在应用程序开发的过程中&#xff0c;特别是在构建…

力扣初级算法(旋转矩阵)

力扣初级算法(旋转矩阵) 每日一算法&#xff1a;旋转矩阵 学习内容&#xff1a; 1.问题&#xff1a; 给你一幅由 N N 矩阵表示的图像&#xff0c;其中每个像素的大小为 4 字节。请你设计一种算法&#xff0c;将图像旋转 90 度。 不占用额外内存空间能否做到&#xff1f; 2.…

React源码解析18(3)------ beginWork的工作流程【mount】

摘要 OK&#xff0c;经过上一篇文章。我们调用了&#xff1a; const root document.querySelector(#root); ReactDOM.createRoot(root)生成了FilberRootNode和HostRootFilber。 并且二者之间的对应关系也已经确定。 而下一步我们就需要调用render方法来讲react元素挂载在ro…

途乐证券-保险消费者信心延续恢复态势 健康险、意外险增购意愿上

今年以来&#xff0c;稳妥顾客决心延续调整康复态势。我国稳妥保证基金有限责任公司&#xff08;以下简称“稳妥保证基金公司”&#xff09;近来发布数据显现&#xff0c;2023年二季度&#xff0c;我国稳妥顾客决心指数为67.7&#xff0c;环比下降3.6&#xff0c;同比上升1.2&a…

一文读懂c++语言

一文读懂C语言 C的发展C的设计目标C的特性C的挑战 C的发展 C是一种通用的、高级的编程语言&#xff0c;它是C语言的扩展。C由Bjarne Stroustrup于1983年首次引入&#xff0c;并在之后的几十年中不断发展壮大。C被广泛应用于各种领域&#xff0c;包括系统开发、游戏开发、嵌入式…

keil显示中文代码正常,但是编译中文乱码的问题

Configuration---Editor---Encoding&#xff0c;ANSI或是UTF8&#xff0c;总之这2个&#xff0c;是A就改为U&#xff0c;是U就改为A。 MDK5中文编译乱码&#xff0c;不是显示乱码哦。

Android Camera预览画面变形问题

csdn 问题 安卓camera1在预览时&#xff0c;预览画面看起来被拉伸了&#xff0e; 如图&#xff0c;圆形的盖子&#xff0c;变成椭圆形了&#xff0e; 代码 默认流程&#xff0c;如下为大致的打开摄像头并进行预览显示的代码 private Camera mCamera null; private Surfa…

YOLOv5入门

模型检测 关键参数 weights:训练好的模型文件 source: 检测的目标&#xff0c;可以是单张图片、文件夹、屏幕或者摄像头等 conf-thres: 置信度闯值&#xff0c;越低框越多&#xff0c;越高框越少 iou-thres: IOU闻值&#xff0c;越低框越少&#xff0c;越少框越多 torch.hu…

windows安装apache-jmeter-5.6.2教程

目录 一、下载安装包&#xff08;推荐第二种&#xff09; 二、安装jmeter 三、启动jmeter 一、下载安装包&#xff08;推荐第二种&#xff09; 1.官网下载&#xff1a;Apache JMeter - Download Apache JMeter 2.百度云下载&#xff1a;链接&#xff1a;https://pan.baidu.…

vivo 场景下的 H5无障碍适配实践

作者&#xff1a;vivo 互联网前端团队- Zhang Li、Dai Wenkuan 随着信息无障碍的建设越来越受重视&#xff0c;开发人员在无障碍适配中也遇到了越来越多的挑战。本文是笔者在vivo开发H5项目做无障碍适配的实践总结。本文主要介绍了在前端项目中常用的无障碍手势和无障碍属性&am…