8-异常与错误

news2024/11/19 17:50:39

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操作符获取信息失败时,会抛出这个异常

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

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

相关文章

SpringBoot打war包并配置外部Tomcat运行

简介 由于其他原因&#xff0c;我们需要使用SpringBoot打成war包放在外部的Tomcat中运行,本文就以一个案例来说明从SpringBoot打war包到Tomcat配置并运行的全流程经过 环境 SpringBoot 2.6.15 Tomcat 8.5.100 JDK 1.8.0_281 Windows 正文 一、SpringBoot配置打war包 第一步&a…

echarts 图表不显示的问题

是这样的&#xff0c;点击详情&#xff0c;再点击统计&#xff0c;切换的时候就不会显示echarts图表&#xff0c;刚开始使用的是next Tick&#xff0c;没有使用定时器&#xff0c;后来加上了定时器就实现了如下所示&#xff1a; 代码是如下 const chartContainer ref(null); …

开发一个SDK(starter)

1.创建项目 将pom.xml中build删除掉

pikachu靶场(unsafe upfileupload(文件上传)通关教程)

目录 client check 1.在桌面新建一个文本文档 2.保存为.png格式 3.打开网站 4.按照图中操作 5.点击forward 6.访问 MIME type 1.新建一个php文件&#xff0c;里面写上 2.上传文件&#xff0c;就是我们保存的文件 3.打开抓包工具&#xff0c;点击开始上传 4.修改Conen…

服务器主板电池

一、什么是服务器纽扣电池&#xff1f; 服务器纽扣电池&#xff0c;也叫CMOS电池&#xff0c;是一种非常小型的电池&#xff0c;通常与服务器主板上的CMOS芯片相结合&#xff0c;用于储存BIOS设置、时钟和其他关键系统信息。这种电池的体积通常比一枚硬币还小&#xff0c;而且…

RT-DETR:端到端的实时Transformer检测模型(目标检测+跟踪)

博主一直一来做的都是基于Transformer的目标检测领域&#xff0c;相较于基于卷积的目标检测方法&#xff0c;如YOLO等&#xff0c;其检测速度一直为人诟病。 终于&#xff0c;RT-DETR横空出世&#xff0c;在取得高精度的同时&#xff0c;检测速度也大幅提升。 那么RT-DETR是如…

数据库(13)——DQL分组查询

语法 SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段名 [HAVING 分组后过滤条件] 示例 原始表&#xff1a; 根据性别分组并统计人数 select sex,count(*) from information group by sex; 根据性别分组&#xff0c;并求年龄的平均值&#xff1a;

2024抖音流量认知课:掌握流量底层逻辑,明白应该选择什么赛道 (43节课)

课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/89360865 更多资源下载&#xff1a;关注我。 课程目录 01序言&#xff1a;拍前请看.mp4 02抖音建模逻辑1.mp4 03抖音标签逻辑2.mp4 04抖音推流逻辑3.mp4 05抖音起号逻辑4.mp4 06养号的意义.mp4 0…

Java | Leetcode Java题解之第123题买卖股票的最佳时机III

题目&#xff1a; 题解&#xff1a; class Solution {public int maxProfit(int[] prices) {int n prices.length;int buy1 -prices[0], sell1 0;int buy2 -prices[0], sell2 0;for (int i 1; i < n; i) {buy1 Math.max(buy1, -prices[i]);sell1 Math.max(sell1, b…

Bean作用域和生产周期已经Bean的线程安全问题

bean 的作用域 单例(Singletion) : Spring 容器中只有一个 bean &#xff0c;这个 bean 在整个应用程序内共享。 原话(Prototype) : 每次 getBean()&#xff0c; 都是不同的bean&#xff0c;都会创建一个实例。 请求(Request)&#xff1a;每个HTTP请求都会创建一个新的 Bean …

开发者工具-sources(源代码选项)

一、概要说明 源代码面板从视觉效果上分为三个区域&#xff1a;菜单区、内容区、监听区。 菜单区里面有5个子分类&#xff1a; 网页(Page)&#xff1a;指页面源&#xff0c;包含了该页面中所有的文件&#xff0c;即使多个域名下的文件也都会展示出来&#xff0c;包括iframe…

束测后台实操文档2-OpenWrt

束测后台实操文档1-PVE、PBS 上面文&#xff0c;把proxmox装好并添加好PBS上的镜像存储空间后&#xff0c;还原已经做好的镜像基本上就可以在已有的镜像下开展工作了。 调试的PVE环境一般两个网口&#xff0c;一个外网wan&#xff0c;一个子网lan&#xff0c;虚拟机一般在lan…

【redis】宝塔,线上环境报Redis error: ERR unknown command del 错误

两种方式&#xff1a; 1.打开宝塔上的redis&#xff0c;通过配置文件修改权限&#xff0c;注释&#xff1a;#rename-command DEL “” 2.打开服务器&#xff0c;宝塔中默认redis安装位置是&#xff1a;cd /www/server/redis 找到redis.conf,拉到最后&#xff0c;注释#rename-co…

大语言模型技术系列讲解:大模型应用了哪些技术

为了弄懂大语言模型原理和技术细节&#xff0c;笔者计划展开系列学习&#xff0c;并将所学内容从简单到复杂的过程给大家做分享&#xff0c;希望能够体系化的认识大模型技术的内涵。本篇文章作为第一讲&#xff0c;先列出大模型使用到了哪些技术&#xff0c;目的在于对大模型使…

C++设计模式-策略模式

文章目录 27. 策略模式 运行在VS2022&#xff0c;x86&#xff0c;Debug下。 27. 策略模式 策略模式让算法的选择与使用独立开来&#xff0c;使得代码更灵活、可扩展和易维护。应用&#xff1a;如在游戏开发中&#xff0c;AI角色需要根据环境和条件做出不同的行为&#xff0c;如…

基于云服务器使用DreamBooth训练主体

资源整理 参考教程&#xff1a;StableDiffusion/NAI DreamBooth自训练全教程 - 知乎 (zhihu.com) 云服务器平台&#xff1a;AutoDL算力云 | 弹性、好用、省钱。租GPU就上AutoDL 镜像链接&#xff1a;CrazyBoyM/dreambooth-for-diffusion/dreambooth-for-diffusion、 代码仓…

使用Python操作Git

大家好&#xff0c;当谈及版本控制系统时&#xff0c;Git是最为广泛使用的一种&#xff0c;而Python作为一门多用途的编程语言&#xff0c;在处理Git仓库时也展现了其强大的能力。通过Python&#xff0c;我们可以轻松地与Git仓库进行交互&#xff0c;执行各种操作&#xff0c;从…

为参数设置默认值

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 调用函数时&#xff0c;如果没有指定某个参数将抛出异常&#xff0c;为了解决这个问题&#xff0c;我们可以为参数设置默认值&#xff0c;即在定义函…

Blueprints - Collision Presets相关

一些以前的学习笔记归档&#xff1b; 在Static Mesh或SkeletalMesh等的属性中&#xff0c;都有Collision Presets&#xff1a; 其中Oject Type只是一个枚举参数&#xff0c;代表设置该Actor为什么类型&#xff0c;Collision Responses代表该Actor对各种类型的Actor有什么反应&a…

MYSQL四大操作——查!查!查!

目录 简洁版&#xff1a; 详解版&#xff1a; SQL通用语法&#xff1a; 分类&#xff1a; 1. DDL —库 1.1 查询&#xff1a; 1.2 创建&#xff1a; 1.3 删除 1.4 使用库 2. DDL—表 2.1 查询 2.1.1 查询当前库的所有表&#xff1a; 2.1.2 查询表结构 &#xff1a; 2.1.…