8-异常与错误

8-异常与错误

  • 1、简介
  • 2、异常处理
    • 2.1 抛出异常
    • 2.2 捕获异常
    • 2.3 匹配顺序
  • 3、异常说明
  • 4、构造函数中的异常
  • 5、析构函数中的异常
  • 6、标准库异常

1、简介

在程序编码过程中难免会出现错误,主要有:语法错误、逻辑错误、功能错误等,当我们面对以上错误时处理主要针对在实际运行环境中发生,却在设
计、编码和测试阶段无法预料的,当面对异常时,有三种典型的处理机制:

  • 通过返回值返回错误信息
    • 所有局部对象都能正确地被析构
    • 逐层判断,流程繁琐
  • 借助setjmp,/longjmp远程跳转(不建议使用,这种效率最高,但是如果使用不当,会造成更加严重的后果)
    • 一步到位,流程简单
    • 某些局部对象可能因此丧失被析构的机会
  • 抛出—捕获异常对象(c++推荐使用)
    • 形式上一步到位,流程简单
    • 实际上逐层析构局部对象,避免内存泄漏

2、异常处理

2.1 抛出异常

语法:throw 异常对象

  • 可以抛出基本类型的对象,如:
void foo(){
	FILE * txt = fopen("./a.txt", "r");
	if (!txt){
		cout << "文件打开失败" << endl;
		throw - 1;
	}
	cout << "文件打开成功" << endl;
}
  • 可以抛出类类型的对象
void bar(){
	FILE * txt = fopen("./a.txt", "r");
	if (!txt){
		cout << "文件打开失败" << endl;
		throw A(3);//以匿名临时对象抛出的异常,编译器会做优化,减少一次拷贝
	}
	cout << "文件打开成功" << endl;
}
  • 不可以抛出局部对象的指针
void fu(){
	FILE * txt = fopen("./a.txt", "r");
	if (!txt){
		cout << "文件打开失败" << endl;
		A a = A(3);// 构造A
		throw &a; // 这里会进行一次拷贝
	}
	cout << "文件打开成功" << endl;
}

解释:这是因为在c++中所有的异常都是抛向C++标准库中的,在标准库中会保存一份异常抛出对象的副本,而在异常抛出之后,原抛出异常的地方会进行销毁处理。

2.2 捕获异常

语法:try{}catch(…)

  • 建议是在catch子句中使用引用接收异常对象,避免因拷贝构造带来的性能损失。
    int main(){
    	try{
    		C08_01();
    	}
    	catch (C08_B& b){// 这里就不会进行拷贝了,直接使用的是标准库里的对象
    		cout << "捕获到异常B" << endl;
    		b.info();
    	}
    	catch (C08_C& c){
    		cout << "捕获到异常C" << endl;
    		c.info();
    	}
    	catch (int & e){
    		cout << e << endl;
    	}
    	catch (C08_A a){// 这里会进行一次拷贝
    		a.info();
    	}
    	cout << "程序执行成功" << endl;
    	return 0;
    }
    
- 推荐使用匿名临时对象的形式抛出异常
```c++
void bar(){
	FILE * txt = fopen("./a.txt", "r");
	if (!txt){
		cout << "文件打开失败" << endl;
		throw A(3);//以匿名临时对象抛出的异常,编译器会做优化,减少一次拷贝
	}
	cout << "文件打开成功" << endl;
}
  • 异常对象必须允许被拷贝构造和析构
    在这里插入图片描述

2.3 匹配顺序

根据异常对象的类型自上而下的顺序匹配,而不是最优匹配,因此对子类类型异常的捕获不要放在基类类型异常的捕获后面。
在这里插入图片描述

3、异常说明

异常说明是函数原型的一部分,旨在说明函数可能抛出的异常类型。

  • 语法格式:
	返回类型 函数名(参数列表) throw(异常类型1,异常类型2,...){函数体}
  • 异常说明是一种承诺,承诺函数不会抛出异常说明以外的异常类型。
    • 如果函数抛出了异常说明以外的异常类型,那么该异常将无法捕获,会导致进程中止
      在这里插入图片描述

    • std::unexpected()->std::terminate()->abort

    • 隐式抛出异常的函数也可以列出它的异常说明
      在这里插入图片描述

    • 异常说明可以没有也可以为空
      注意:
      1:没有异常说明时,表示可能抛出任何类型的异常,比如void foo(){};代表foo这个函数可能抛出任何类型的异常
      2:异常说明为空时,表示不会抛出任何类型的异常,比如void foo()throw(){}

    • 异常说明在函数的声明和定义中必须保持严格一致,否则将导致编译错误
      在这里插入图片描述

      • 忽略异常,不做处理
        在这里插入图片描述

4、构造函数中的异常

  • 构造函数可以抛出异常,某些时候还必须抛出异常
    • 构造过程中可能遇到各种错误,比如内存分配失败
    • 构造函数没有返回值,无法通过返回值通知调用者
  • 构造函数抛出异常,对象将被不完整构造,而一个被不完整构造的对象,其析构函数永远不会被执行
    • 所有对象形式的成员变量,在抛出异常的瞬间,都能得到正确地析构(构造函数的回滚机制)
    • 所有动态分配的资源,必须在抛出异常之前,自己手动释放,否则将形成资源的泄漏。
class C08_AA{
	public:
		C08_AA(){ 
			cout << "AA类构造函数" << endl; 
		}
		~C08_AA(){ cout << "AA类的析构函数" << endl; }
};
class C08_CC{
private:
	C08_AA aa;
	FILE *A;
public:
	C08_CC(){
		cout << "CC类构造函数" << endl;
		A = fopen("./a.txt", "r");
		if (!A){
			// 对于动态申请的资源,必须自己手动释放
			throw - 1;// 在构造函数中出现异常,那么所有对象形式的成员变量,在抛出异常的瞬间,都能得到正确地析构(构造函数的回滚机制)
		}	
	}
	~C08_CC(){
		cout << "CC类析构函数" << endl;
	}
};

int main(){
	try{
		C08_CC cc;// 如果cc是完整函数对象,则会调用cc的析构函数,如果cc是残缺对象,则不会调用cc的析构函数
	}
	catch(...){// 捕获任意异常
		
	}
	C08_CC cc;
	return 0;
}

5、析构函数中的异常

不要在析构函数中主动抛出异常

  • 析构函数只会在两种情况下被系统调用:
    1:正常的销毁对象:当对象离开作用域或者显式的使用delete
    2:异常的销毁对象:在异常传递的堆栈辗转开解过程中销毁对象
  • 需要注意的是,对于第二种情况,此时系统中存在异常,而此时的析构函数中又抛出了异常,这时C++将通过std::terminate()函数,令进程中止
    所以为了避免出现这种情况,在析构函数中,对于可能引发异常的操作,尽量在析构函数内部处理掉,不要主动抛出异常。
class C08_D{
public:
	~C08_D(){
		throw "析构函数抛出的异常";	
	}
};
int main(){
	try{
		C08_D d;
		oneThrow();// 这里已经抛出了异常
	}// 此时d中析构函数中也抛出了异常,此时这个异常就捕获不到,然后就会被系统杀死
	catch (const char* a){
		cout << a << endl;
	}
	catch (...){

	}
}

6、标准库异常

在这里插入图片描述

  • exception:抽象类
  • runtime_error: 抽象类
  • logic_error:抽象类
  • overflow_error:上溢异常,一般用于容器满了的情况下
  • underflow_error:下溢异常,一般用于容器空了的情况下
  • invalid_argument:无效参数,一般用于实参和形参之间的数据不匹配
  • length_error:长度错误
  • out_of_range:超出范围
  • bad_alloc:new操作符申请失败,会抛出这个异常
  • bad_cast:动态类型转换中引用的转换失败,会抛出这个异常
  • bad_type_id:使用typeid操作符获取信息失败时,会抛出这个异常

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DAQmx Connect Terminals (VI) 信号路由作用及意义

DAQmx Connect Terminals是一个LabVIEW虚拟仪器&#xff08;VI&#xff09;&#xff0c;用于配置和连接数据采集系统中的物理终端或虚拟终端。这一功能在配置复杂的数据采集&#xff08;DAQ&#xff09;系统时非常重要&#xff0c;因为它允许用户在不改变硬件连接的情况下&…

景源畅信数字:抖音新手如何找好自己的发布领域?

在短视频的浪潮中&#xff0c;抖音以其独特的魅力吸引了众多用户。对于刚踏入这个平台的新手来说&#xff0c;找到适合自己的发布领域至关重要。那么&#xff0c;如何在这个充满竞争的平台上找到自己的定位呢?接下来&#xff0c;就让我们一起来探讨这个问题。 一、明确兴趣爱好…

活动选择问题(贪心法)

目录 问题概述 实例分析 代码实现 问题概述 实例分析 求解蓄栏保留问题。农场有n头牛,每头牛会有一个特定的时间区间[b,e]在蓄栏里挤牛奶,并且一个蓄栏里任何时刻只能有一头牛挤奶。现在农场主希望知道最少蓄栏能够满足上述要求,并给出每头牛被安排的方案。对于多种可行方案…

情感读本期刊万方收录综合期刊投稿

《情感读本》杂志是由国家新闻出版总署批准&#xff0c;湖北省新闻出版广电局主管&#xff0c;湖北省期刊协会主办的正规综合类期刊。《情感读本》是一本以推动和发展情感教育、素质教育、人文教育为己任&#xff0c;奉行“立足教育&#xff0c;服务社会”的办刊宗旨&#xff0…

ChatGPT产品创意,直接出概念图

直接问&#xff0c;“给我一个创意点子” AI7号 它推荐我做一个智能家居植物管理系统&#xff0c;嗯&#xff0c;很小众的样子。直接让它出一张概念图吧。 像模像样&#xff0c;一张图太单薄了&#xff0c;再来5张。 呃...做了4张&#xff0c;下面还有每张图的说明。 你觉得怎…

(奇幻森林)POLYGON - Enchanted Forest - Nature Biomes - 3D Environment Art by Synty

各种雄伟的树木,装饰着优雅简化的树叶,在头顶形成了一个天堂般的树冠,在苔藓覆盖的森林地面上投下了宁静的咒语。 每一项资产,从引人入胜的环境材料到平缓的波浪状山丘,都经过精心制作,将您带到魔法和自然融合的地方。POLYGON-魔法森林-自然生物技术为数字领域注入真正魔…

实战16:基于apriori关联挖掘FP-growth算法挖掘关联规则的手机销售分析-代码+数据

直接看视频演示: 基于apriori关联挖掘关联规则的手机销售分析与优化策略 直接看结果: 这是数据展示: 挖掘结果展示: 数据分析展示:

矩阵短视频:成都科成博通文化传媒公司

重塑内容生态与传播格局、在数字化时代&#xff0c;短视频以其独特的形式和高效的传播能力&#xff0c;迅速崛起并成为了社交媒体领域的明星。成都科成博通文化传媒公司​而“矩阵短视频”作为短视频领域的一种新兴策略&#xff0c;正以其独特的优势&#xff0c;逐渐重塑内容生…

【JAVASE】String 类常用方法

1、字符串构造 String类提供的构造方式很多&#xff0c;常用的有三种。 &#xff08;1&#xff09;使用常量串构造 例如&#xff1a; &#xff08;2&#xff09;直接new String对象 例如&#xff1a; &#xff08;3&#xff09;使用字符数组进行构造 例如&#xff1a; 2…

20240531在飞凌的OK3588-C开发板上跑原厂的Buildroot测试ETH0接口【仅供参考】

20240531在飞凌的OK3588-C开发板上跑原厂的Buildroot测试ETH0接口 2024/5/31 20:28 rootrk3588-buildroot:/# ifconfig eth0 up rootrk3588-buildroot:/# ifconfig eth1 up rootrk3588-buildroot:/# ifconfig rootrk3588-buildroot:/# rootrk3588-buildroot:/# ifconfig eth1…

Linux CFS调度器之周期性调度器scheduler_tick函数

文章目录 前言一、简介二、源码分析2.1 scheduler_tick2.2 task_tick2.3 entity_tick2.4 check_preempt_tick2.5 resched_curr 参考资料 前言 Linux内核调度器主要是主调度器和周期性调度器&#xff0c;主调度器请参考&#xff1a;Linux 进程调度之schdule主调度器 一、简介 …

如何在IDEA中实现类似Linux命令那样的外部传参

【背景说明】 IDEA中执行一个程序时&#xff0c;如何就在程序一开始执行给传入你给的参数呢&#xff1f; 【说明】 public static void main(String[] args) throws Exception {} 说明&#xff1a;其实java中main方法里的args这个参数&#xff0c;就是用于接收外部传参的。…

C# 写一个简单的Windows Service的服务程序

项目创建及设定部分 使用VS2019创建项目&#xff0c;选择C# Service的选项 按照你喜欢的方式命名&#xff0c;我这边就默认了 添加安装服务&#xff0c;在Service1.cs[Design]中 在设计界面右击&#xff0c;选择如下的"Add Installer" 在出现的"ProjectInstall…

Ubuntu server 24 (Linux) Snort3 3.2.1.0 Guardian IPtables 联动实战 主动防御系统(ids+ips)

一 Snort3 安装配置&#xff0c;参考:Ubuntu server 24 安装配置 snort3 3.2.1.0 网络入侵检测防御系统 配置注册规则集-CSDN博客 二 安装主动防御程序Guardian 1 下载&#xff0c;解压 tar zxvf guardian-1.7.tar.gz cd guardian-1.7/ 2 配置 #拷贝文件 sudo cp guard…

如何从浅入深理解transformer?

前言 在人工智能的浩瀚海洋中&#xff0c;大模型目前无疑是其中一颗璀璨的明星。从简单的图像识别到复杂的自然语言处理&#xff0c;大模型在各个领域都取得了令人瞩目的成就。而在这其中&#xff0c;Transformer模型更是成为大模型技术的核心。 一、大模型的行业发展现状如…

docker删除所有容器

笔记 要使用 Docker 删除所有容器&#xff08;无论是停止的还是正在运行的&#xff09;&#xff0c;可以按照以下步骤操作&#xff1a; 1. **删除所有正在运行的容器**&#xff1a; 首先&#xff0c;您需要停止所有正在运行的容器。可以使用以下命令&#xff1a; dock…

官方正版 | FastCopy - Windows 上最快的文件复制&备份软件

『FastCopy 软件概述』 FastCopy 是一款高性能的文件复制和备份工具&#xff0c;专为 Windows 操作系统设计。它以其卓越的速度和丰富的功能&#xff0c;在用户中赢得了良好的声誉。以下是 FastCopy 的主要特点和优势&#xff1a; 速度优化&#xff1a;FastCopy 通过多线程、异…

c# - 运算符 << 不能应用于 long 和 long 类型的操作数

Compiler Error CS0019 c# - 运算符 << 不能应用于 long 和 long 类型的操作数 处理方法 特此记录 anlog 2024年5月30日

Day10:平面转换、渐变色

目标&#xff1a;使用位移、缩放、旋转、渐变效果丰富网页元素的呈现方式。 一、平面转换 1、简介 作用&#xff1a;为元素添加动态效果&#xff0c;一般与过渡配合使用。 概念&#xff1a;改变盒子在平面内的形态&#xff08;位移、旋转、缩放、倾斜&#xff09;。 平面转换…

工业安全智勇较量,赛宁网安工业靶场决胜工业网络攻防对抗新战场

2024年1月30日&#xff0c;工信部发布《工业控制系统网络安全防护指南》&#xff08;工信部网安〔2024〕14号&#xff09;&#xff0c;围绕安全管理、技术防护、安全运营、责任落实四方面提出安全防护要求&#xff0c;强调聚焦安全薄弱关键环节&#xff0c;强化技术应对策略&am…