C++进阶--异常

C语言传统的处理方式

  1. 终止程序:在发生错误时直接终止程序的运行,可以通过assert宏来进行实现。如assert(condition),其中condition不满足要求时,将会使程序立刻停止执行,并输出相关错误信息。这种方式的确定是用户很难接受突然的程序终止,它没有提供任何机会来进行修复和处理
  2. 返回错误码:在函数体内,如果发生错误,将错误码作为函数的返回值进行返回。通常情况下0表示返回成功,非零值表示错误,并且根据对应返回值做出相应的处理。

这些方式在实际应用中对代码的可读性和可维护性是非常低的,尤其在大型项目中。

C++异常的概念

在 C++ 中,异常是指程序在运行过程中遇到的一些意外情况或错误,导致当前代码无法正常执行下去的情况。这些异常可能是由于程序逻辑错误、外部环境变化或者运行时错误引起的。

异常处理机制允许程序员在代码中标识出可能引发异常的代码块,并提供一种机制来捕获和处理这些异常,以便程序在出现问题时能够以一种更加优雅和可控的方式来处理异常情况,而不至于导致程序崩溃或者无法正常执行。

在 C++ 中,异常处理的主要机制包括以下几个关键组件:

  1. 抛出异常(Throwing Exceptions):当程序遇到错误或异常情况时,可以使用 throw 关键字来抛出一个异常。异常可以是任何类型的数据,但通常是标准库中的异常类或者自定义的异常类的实例。

  2. 捕获异常(Catching Exceptions):在代码中使用 try 块来标识可能会引发异常的代码段,然后使用 catch 块来捕获和处理这些异常。catch 块可以指定捕获的异常类型,以及对应的处理逻辑。

  3. 异常传递(Exception Propagation):如果在 try 块中的代码抛出了异常,程序会在当前函数中查找匹配的 catch 块来处理异常。如果找不到匹配的 catch 块,则异常会在当前函数中被终止,并且会将异常传递给调用栈上的上一层函数,继续寻找匹配的 catch 块。

  4. 清理资源(Resource Cleanup):在异常处理过程中,可以使用 finally 块来执行一些清理工作,确保资源在程序终止时得到正确释放。

使用异常处理机制可以使程序的错误处理逻辑更加清晰和灵活,提高了程序的健壮性和可维护性。

异常的使用

异常的抛出和匹配规则

异常的抛出和匹配规则是异常处理机制的核心。
异常抛出和匹配规则的基本概念:

  1. 异常的抛出(Throwing Exceptions)

    • 异常可以由 throw 关键字抛出。抛出异常时,可以使用任何类型的表达式,通常是一个异常对象的实例,例如:
      throw std::runtime_error("Something went wrong");
      
    • 抛出的异常可以是任何类型,包括标准库提供的异常类型,或者用户自定义的异常类的实例。
  2. 异常的匹配(Exception Matching)

    • 异常的匹配是指在 try 块中捕获并处理异常的过程。
    • try 块中的代码抛出异常时,程序会在 try 块后面的 catch 块中寻找与抛出的异常类型相匹配的处理程序。
    • catch 块可以使用异常类型来指定要捕获的异常。如果抛出的异常的类型与 catch 块中指定的类型匹配,那么相应的 catch 块就会执行。
    • 异常类型可以是异常类的实例、指针、引用或者任何继承自 std::exception 的类型。
  3. 异常的传递(Exception Propagation)

    • 如果在 try 块中的代码抛出异常,程序会在当前函数中查找匹配的 catch 块来处理异常。
    • 如果当前函数中没有匹配的 catch 块,那么异常会传播到调用当前函数的函数中,依此类推,直到找到匹配的 catch 块为止。
    • 如果在调用栈上找不到匹配的 catch 块,程序会调用 std::terminate() 来终止程序的执行。

简单使用

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;
	cout << "=====================" << endl;

}

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

	return 0;
}

在这里插入图片描述

异常的缺陷

double Division(int a, int b)
{
	// 当b == 0时抛出异常
	if (b == 0)
		throw "Division by zero condition!";
	else
		return ((double)a / (double)b);
}


void fxx()
{
	int i = 0;
	cin >> i;
	if (i % 2 == 0)
	{
		throw 1;
	}
}

void Func()
{
	int len, time;
	cin >> len >> time;
	cout << Division(len, time) << endl;
	try
	{
		fxx();
	}
	catch (int x)
	{
		cout <<__LINE__<<"捕获异常:" << x << endl;
	}

	cout << "=====================" << endl;

}

int main()
{
	try 
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (int x)
	{
		cout << __LINE__ <<"捕获异常:"<< x << endl;
	}

	cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;

	return 0;
}

在这里插入图片描述

异常安全

异常安全是指程序在面对异常时依然能够保持系统的一致性和稳定性,不会导致资源泄漏或数据损坏。异常安全性分为三个级别:

  1. 基本异常安全(Basic Exception Safety):即使发生异常,程序的内部状态不会被破坏。程序能够保证在异常抛出前的状态与异常抛出后的状态之间存在一种合理的约束关系。例如,内存不会泄漏,对象不会处于不一致的状态。

  2. 强异常安全(Strong Exception Safety):即使发生异常,程序的内部状态也不会改变。程序能够保证在异常抛出前的状态与异常抛出后的状态完全一致。这意味着所有操作要么成功完成,要么没有执行任何修改。通常需要使用事务性或回滚操作来实现。

  3. 无异常安全(No-Throw Guarantee):程序不会抛出任何异常。这意味着所有的操作都能够在不引发异常的情况下成功完成。通常用于对性能和可靠性要求极高的系统,例如实时系统。

实现异常安全的方法通常包括以下几种:

  • 使用 RAII(资源获取即初始化)技术,通过对象的生命周期来管理资源,确保在对象销毁时资源得到正确释放
  • 在异常发生时使用异常处理机制来回滚操作,恢复到先前的状态。
  • 使用事务性操作来确保操作的原子性,当发生异常时可以回滚整个操作。
  • 使用智能指针、容器等标准库提供的异常安全的工具和数据结构,减少手动管理资源的复杂度。

未知异常

一般来说,如果我们不确定哪个地方会出现错误,我们可以增加一个捕获模块:用来显示未知的异常情况

double Division(int a, int b)
{
	// 当b == 0时抛出异常
	if (b == 0)
		throw "Division by zero condition!";
	else
		return ((double)a / (double)b);
}


void fxx()
{
	int i = 0;
	cin >> i;
	if (i % 2 == 0)
	{
		throw 10;
	}
}

void Func()
{
	int len, time;
	cin >> len >> time;
	cout << Division(len, time) << endl;
	fxx();
}

int main()
{
	try
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}
	catch (const string& err)
	{
		cout << err << endl;
	}
	catch (...) // 任意类型的异常
	{
		cout << "未知异常" << endl;
	}

	return 0;
}

在这里插入图片描述

异常继承体系

这里,将模拟一般情况异常抛出的情况,利用多态的原理来捕获对应哪个流程的异常。

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 CacheException : public Exception
{
public:
	CacheException(const string& errmsg, int id)
		:Exception(errmsg, id)
	{}

	virtual string what() const
	{
		string str = "CacheException:";
		str += _errmsg;
		return str;
	}
};

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("权限不足", 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()
{
	srand(time(0));

	// 20:15继续
	while (1)
	{
		Sleep(1000);

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

	return 0;
}

在这里插入图片描述

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

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

相关文章

Golang基础3-函数、nil相关

函数 需要声明原型支持不定参数 func sum(numbers ...int)int支持返回多值支持递归支持命名返回参数 // 命名返回参数 func add(a, b int) (sum int) {sum a breturn // 这里不需要显式地写出返回值&#xff0c;因为已经在函数签名中声明了命名返回参数 } 支持匿名函数、闭包…

Jackson 2.x 系列【30】Spring Boot 集成之数据脱敏

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Jackson 版本 2.17.0 本系列Spring Boot 版本 3.2.4 源码地址&#xff1a;https://gitee.com/pearl-organization/study-jaskson-demo 文章目录 1. 概述2. 实现思路3. 案例演示3.1 脱敏规则3.2 自…

图像处理之Retinex算法(C++)

图像处理之Retinex算法&#xff08;C&#xff09; 文章目录 图像处理之Retinex算法&#xff08;C&#xff09;前言一、单尺度Retinex&#xff08;SSR&#xff09;1.原理2.代码实现3.结果展示 二、多尺度Retinex&#xff08;MSR&#xff09;1.原理2.代码实现3.结果展示 三、带色…

Linux加强篇-存储结构与管理硬盘(一)

目录 ⛳️推荐 从“/”开始 物理设备命名规则 文件系统与数据资料 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 从“/”开始 Linux系统中一切都是文件&#xff0c;都是从“…

deep learning

谷歌在线notebook 一、基本数据类型与用法 1.torch.tensor(张量) 按照维度不同(中括号的对数)&#xff0c;可以用torch.tensor创建scalar(标量)、vector(向量)、matrix(矩阵)&#xff0c; 一般的&#xff0c;一维是标量&#xff0c;二维是向量&#xff0c;三维是矩阵&#…

银河麒麟V10 SP1服务器客户端定时数据同步

银河麒麟V10 SP1服务器客户端定时数据同步 0.概述 当前只测试了将数据从客户端往服务端推送&#xff0c;两个客户端分别推送不同的数据 1.环境 三台电脑均为银河麒麟V10SP1桌面操作系统 服务器IP&#xff1a;192.168.1.51 用户名&#xff1a;wlh 客户端IP&#xff1a;192…

LabVIEW和MES系统的智能化车间数据对接

LabVIEW和MES系统的智能化车间数据对接 随着工业4.0时代的到来&#xff0c;智能制造成为推动制造业高质量发展的重要手段。其中&#xff0c;数字化车间作为智能制造的重要组成部分&#xff0c;其设计与实现至关重要。在数字化车间环境下&#xff0c;如何利用LabVIEW软件与MES系…

解析SoC芯片:构建智能设备的核心技术

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

linux磁盘原理

在linux系统中&#xff0c;对磁盘进行管理与windows系统类似&#xff0c;都要先分区&#xff0c;格式化&#xff0c;创建文件系统&#xff0c;挂载目录&#xff0c;数据写入

【PHP开发工程师详细讲解分析】——网站注册账号(头像的上传操作),让自己喜欢的头像更换畅通无阻

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

便携式应急指挥箱规格参数

概况: 微缩型的无线视频音频传输的机动挥所。体积小、重量轻、公配电方便、携带便携、功能齐全。可进行单兵作战&#xff0c;通过此无线音频视频传输的指挥箱能完成现场图像、语音、数据的采集等功能&#xff0c;可以通过5G/4G/WIFI等多种无线网络完成传输的需求&#xff0c;或…

计算机网络相关知识总结

一、概述 计算机网络可以极大扩展计算机系统的功能机器应用范围&#xff0c;提高可靠性&#xff0c;在为用户提供放方便的同时&#xff0c;减少了整体系统费用&#xff0c;提高性价比。 计算机网络的功能主要有&#xff1a;1. 数据共享&#xff1b;2. 资源共享&#xff1b;3. 管…

echart坑

echart坑 原因&#xff1a; 引用了echarts里面的init方法显示没有定义 解决的方法 将import echarts from echarts 的引入方式改为&#xff1a; import * as echarts from echarts

【vue2】实现微信截图(复制图片)在项目内可粘贴

需求 后台管理在上传图片地方需要将复制的图片粘贴上传 一、添加事件 在原有上传组件的基础上添加 paste事件 二、方法 onPaste(e) {const items (e.clipboardData || window.clipboardData).items;let blob null;for (let i 0; i < items.length; i) {if (items[i].ty…

学习Rust的第10天:枚举和模式匹配

今天我们来看看一个类似的概念 enums 。 Enums: We saw that in Rust, enums are data types that list possible values, giving a simple and type-safe mechanism to describe alternatives. We looked at how to create enums and use them to represent similar possibili…

Dropout Feature Ranking for Deep Learning Models

摘要 深度神经网络( deep neural networks&#xff0c;DNNs )在多个领域取得了最新的研究成果。不幸的是&#xff0c;DNNs因其不可解释性而臭名昭著&#xff0c;从而限制了其在生物和医疗保健等假说驱动领域的适用性。此外&#xff0c;在资源受限的环境下&#xff0c;设计依赖…

沐风老师3dMax万有引力插件ToGround使用方法详解

3dMax万有引力插件ToGround使用教程 3dMax万有引力插件ToGround&#xff0c;用于在复杂地形&#xff08;曲面&#xff09;上将对象放置在适当高度的实用工具。例如&#xff1a;将大量的人、植物和汽车快速放置在一个街道、公园和小跑道高度不同的区域尤其有用。 【适用版本】 …

android openGL ES详解

1、渲染线程与主线程的通信 两个线程之间的通信可以用如下方法: 在主线程中的 GLSurfaceView 实例可以调用 queueEvent( &#xff09;方法传递一个 Runnable 给后台渲染线程&#xff0c;渲染线程可以调用 Activity 的 runOnUIThread()来传递事件 (event) 给主线程。 2、顶点…

SQLite FTS3 和 FTS4 扩展(三十二)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite 的命令行 Shell(三十一&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 概述 FTS3 和 FTS4 是 SQLite 虚拟表模块&#xff0c;允许用户执行 对一组文档进行全文搜索。最常见&#xff08;和最有效…

Linux之yum和vim的使用

一、yum的使用 yum 后面跟install要安装的文件名&#xff1a; 若你要安装的文件已经存在&#xff0c;则会出现&#xff1a; 要删除文件&#xff1a; yum remore文件名即可删除 在我们安装完lrzsz之后&#xff0c;可以用rz指令和sz指令&#xff1a; rz指令可以从window窗口中…