【C++进阶9】异常

一、C语言传统的处理错误的方式
- 终止程序,如assert
如发生内存错误,除0错误时就会终止程序 - 返回错误码
需要程序员自己去查找对应的错误
z如系统的很多库的接口函数都是通
过把错误码放到errno中,表示错误
二、C++异常概念
异常:函数无法处理的错误就可以抛出异常
让函数的直接或间接的调用者处理这个错误
- throw: 出现问题时,程序抛出一个异常
通过使用 throw 关键字来完成 - catch: 在您想要处理问题的地方
通过异常处理程序捕获异常 .catch 关键字用于捕获异常
可以有多个catch进行捕获 - try: try 块中的代码标识将被激活的特定异常
它后面通常跟着一个或多个 catch 块
使用方法
double Division(int a, int b)
{// 当b == 0时抛出异常if (b == 0)throw "Division by zero condition!";elsereturn ((double)a / (double)b);
}
void Func()
{int len, time;cin >> len >> time;cout << Division(len, time) << endl;
}int main()
{try{Func();}catch (const char* str) // catch 得跟"Division by zero condition!"类型匹配{cout << str << endl; // Division by zero condition!}return 0;
}
2.1 异常的抛出和匹配原则
- 异常是通过
抛出对象而引发的,该对象的类型决定了应该激活哪个catch的处理代码 - 被
选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个 - 抛出异常对象后,会生成一个异常对象的拷贝,因为抛出的异常对象可能是一个临时对象,
所以会生成一个拷贝对象,这个拷贝的临时对象会在被catch以后销毁
(这里的处理类似于函数的传值返回) - catch(…)可以捕获任意类型的异常,问题是不知道异常错误是什么
- 实际中抛出和捕获的匹配原则有个例外,并不都是类型完全匹配,可以抛出的派生类对象,使用基类捕获,这个在实际中非常实用
正常的异常抛出包含
错误码和错误描述
class Exception
{
public:Exception(int errid, const string& msg): _errid(errid), _errmsg(msg){}const string& GetMsg() const // 引用返回,成员变量出了作用域还在{return _errmsg;}int GetErrid() const{return _errid;}private:int _errid; // 错误码string _errmsg; // 错误描述
};double Division(int a, int b)
{// 当b == 0时抛出异常if (b == 0){// Exception err(1, "除0错误");// throw err;throw Exception(1, "除0错误"); // 用匿名对象,连续的构造+拷贝编译器会优化}else{return ((double)a / (double)b);}
}void Func()
{int len, time;cin >> len >> time;try {cout << Division(len, time) << endl;}catch (char str){cout << str << endl;}cout << "void Func()" << endl;
}int main()
{try{Func();}catch (const Exception& e) {cout << e.GetMsg() << endl;}catch (...) // 捕获任意类型的异常,一般放到最后,防止有些异常没捕获到,导致程序终止{cout << "未知异常" << endl; }return 0;
}
一个公司里面每个人对抛异常的需求不一样
有些人可能只需要一个错误码
有些人则需要更详细的信息
解决方法: 可以搞一个继承体系
比如你是缓存部分我是网络部分
可以写一个子类继承父类Exception
捕获的时候捕两个部分
一个Exception
一个是未知异常
C++很灵活的地方抛子类捕父类
三、自定义异常体系
实际使用中很多公司
都会自定义自己的异常体系
进行规范的异常管理
因为一个项目
如果大家随意抛异常
那么外层的调用者基本没法玩
所以实际中会定义一套继承的规范体系
这样大家抛出的都是继承的派生类对象
捕获一个基类就可以了

服务器开发中通常使用的异常继承体系
class Exception
{
public:Exception(int errid, const string& msg): _errid(errid), _errmsg(msg){}virtual string what() const // 引用返回,成员变量出了作用域还在{return _errmsg;}int GetErrid() const{return _errid;}protected: // 子类可见用保护int _errid; // 错误码string _errmsg; // 错误描述
};class SqlException : Exception // sql专属继承
{
public:SqlException(int errid, const string& msg, const string& sql) // 派生类必须调用父类的构造函数,派生类的特点必须得去复用父类: Exception(errid, msg), _sql(sql){}virtual string what() const // exception写成虚函数进行重写,构造需要的错误信息进行返回{string msg = "SqlException:";msg += _errmsg;msg += "->";msg += _sql;return msg;}protected:string _sql;
};// 出现数据库错误或网络错误
class CacheException : public Exception
{
public:CacheException(const string& errmsg, int id):Exception(id, errmsg){}virtual string what() const{string msg = "CacheException:";msg += _errmsg;return msg;}
};class HttpServerException : public Exception
{
public:HttpServerException(const string& errmsg, int id, const string& type) // 外加一个类型错误:Exception(id, errmsg), _type(type){}virtual string what() const{string msg = "HttpServerException:";msg += _errmsg;msg += "->";msg += _type; return msg;}private:const string _type;
};void SQLMgr() // 数据库
{srand(time(0));if (rand() % 7 == 0){throw SqlException(100, "权限不足", "select * from name = '张三'");}cout << "调用成功" << endl; // 3.数据库出错抛异常,数据库没出错,调用成功.数据库取到数据进行返回
}void CacheMgr() // 缓存
{srand(time(0));if (rand() % 5 == 0){throw CacheException("权限不足", 100);}else if (rand() % 6 == 0){throw CacheException("数据不存在", 101);}SQLMgr(); // 2.缓存出错抛异常,没出错调用数据库
}void HttpServer() // 网络
{// 模拟服务出错srand(time(0));if (rand() % 3 == 0){throw HttpServerException("请求资源不存在", 100, "get");}else if (rand() % 4 == 0){throw HttpServerException("权限不足", 101, "post");}CacheMgr(); // 1.网络出错抛异常,没出错调用缓存
}int main()
{while (1){this_thread::sleep_for(chrono::seconds(1));try {HttpServer();}//catch (const HttpServerException& e) // 当子类和父类同时出现,按顺序走,优先匹配位置近的//{// cout << "子类";// cout << e.what() << endl;//}catch (const Exception& e) // 这里捕获父类对象就可以{// 通过多态拿错误信息.多态指向子类,通过调用子类拿到错误信息 cout << e.what() << endl; // e是父类对象,抛的可能是父类,调的就是父类的what.抛的如果是sql,指向的是子类,调what调用的则是子类的what}catch (...){cout << "Unkown Exception" << endl; // 捕捉未知异常}}return 0;
}
3.1 异常的重新抛出
有可能单个catch不能完全处理一个异常
在进行一些校正处理以后,希望再交给更外层的调用
链函数来处理,catch则可以通过重新抛出将异常传递给更上层的函数进行处理。
double Division(int a, int b)
{// 当b == 0时抛出异常if (b == 0){throw "Division by zero condition!";}return (double)a / (double)b;
}void Func()
{// 这里可以看到如果发生除0错误抛出异常,另外下面的array没有得到释放。// 所以这里捕获异常后并不处理异常,异常还是交给外面处理,这里捕获了再// 重新抛出去。int* array = new int[10]; // 如果抛异常会发生内存泄漏int len, time;cin >> len >> time;try // 所以捕获异常{cout << Division(len, time) << endl;}/*catch (const char* errmsg){cout << errmsg << endl;}*///catch (const char* errmsg)//{// cout << "delete []" << array << endl; // delete[] array;// throw errmsg; // 重新抛出异常,抛之前释放一下//}catch (...) // 各种抛错异常,需要不同的捕获方法,用...便可一劳永逸{cout << "delete []" << array << endl; delete[] array;throw; // 异常的重新抛出,捕到什么抛什么}cout << "delete []" << array << endl; // 如果期望在main函数执行异常,且能够继续完成释放,这是就可以用异常的重新抛出delete[] array;
}int main()
{try{Func();}catch (const char* errmsg){cout << errmsg << endl;}return 0;
}
需要注意的是:
构造函数完成对象的构造和初始化
不要在构造函数中抛出异常
否则可能导致对象不完整
或没有完全初始化
析构函数主要完成资源的清理
不要在析构函数内抛出异常
否则可能导致资源泄漏
C++中异常经常导致资源泄漏的问题
比如:
在new和delete中抛出异常导致内存泄漏
在lock和unlock之间抛出异常导致死锁
C++经常使用RAII来解决以上问题
而RAII在下一篇博客智能指针
会进行专门讲解

本篇博客完,感谢阅读🌹
如有错误之处可评论指出
博主会耐心听取每条意见
相关文章:
【C++进阶9】异常
一、C语言传统的处理错误的方式 终止程序,如assert 如发生内存错误,除0错误时就会终止程序返回错误码 需要程序员自己去查找对应的错误 z如系统的很多库的接口函数都是通 过把错误码放到errno中,表示错误 二、C异常概念 异常:函…...
RecyclerVIew->加速再减速的RecyclerVIew平滑对齐工具类SnapHelper
XML文件 ItemView的XML文件R.layout.shape_item_view <?xml version"1.0" encoding"utf-8"?> <FrameLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"100dp"android:layout_heig…...
突破SaaS产品运营困境:多渠道运营如何集中管理?
随着数字化时代的到来,SaaS(软件即服务)产品已成为企业日常运营不可或缺的工具。然而,在竞争激烈的市场环境下,SaaS产品运营越来越重视多渠道、多平台布局,以更广泛地触及潜在用户,然而…...
智能语音热水器:置入NRK3301离线语音识别ic 迈向智能家居新时代
一、热水器语音识别芯片开发背景 在科技的今天,人们对于生活品质的追求已不仅仅满足于基本的物质需求,更渴望通过智能技术让生活变得更加便捷、舒适。热水器作为家庭生活中不可或缺的一部分,其智能化转型势在必行。 在传统热水器使用中&#…...
Redis集群部署合集
目录 一. 原理简述 二. 集群配置 2.1 环境准备 2.2 编译安装一个redis 2.3 创建集群 2.4 写入数据测试 实验一: 实验二: 实验三: 实验四: 添加节点 自动分配槽位 提升节点为master: 实验…...
【HDFS】关于Hadoop的IPC.Client类的一些整理
org.apache.hadoop.ipc.Client 类是IPC服务的一个客户端。 IPC请求把一个Writable对象当做参数,返回一个Writable对象当做结果value。 一个IPC服务运行在某个端口上,并且由参数class和value class定义。 Router里的IPC.Client对象就两个 有这样一个类:ClientCache 看名字就…...
Swoole v6 能否让 PHP 再次伟大?
现状 传统的 PHP-FPM 也是多进程模型的的运行方式,但每个进程只能处理完当前请求,才能接收下一个请求。而且对于 PHP 脚本来说,只是接收请求和响应请求,并不参与网络通信。对数据库资源的操作,也是一次请求一次有效&am…...
C++ STL Iterator Adapter
1. std::back_insert_iterator 使用 // back_insert_iterator example #include <iostream> // std::cout #include <iterator> // std::back_insert_iterator #include <vector> // std::vector #include <algorithm> // std::copy…...
android-aidl5
aidl类是实现Manager和Service通信的桥梁。 例如在修改Android Wifi功能的时候看到WifiManager管理WifiService; AIDL是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口。 比如onclick(),用oneway修…...
day01-项目介绍及初始化-登录页
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 day01-项目介绍及初始化-登录页一、人力资源项目介绍1.1项目架构和解决方案主要模块解决的问题 二、拉取项目基础代码1.引入库2.升级core-js版本到3.25.5按照完整依…...
华为开发者大会:全场景智能操作系统HarmonyOS NEXT
文章目录 一、全场景智能操作系统 - HarmonyOS NEXT1.1 系统特性1.2 关于架构、体验和生态 二、应用案例2.1 蚂蚁mpaas平台的性能表现 三、新版本应用框架发布3.1 新语言发布3.2 新数据库发布3.3 新版本编译器的发布 四、CodeArts和DataArts4.1 CodeArts4.2 DataArts 五、总结 …...
深度学习二分类评估详细解析与代码实战
深度学习二分类的实战代码:使用 Trainer API 微调模型. https://huggingface.co/learn/nlp-course/zh-CN/chapter3/3 如果你刚接触 自然语言处理,huggingface 是你绕不过去的坎。但是目前它已经被墙了,相信读者的实力,自行解决吧。…...
c++笔记容器详细介绍
C标准库提供了多种容器来存储和管理数据。这些容器属于<vector>, <list>, <deque>, <map>, <set>, <unordered_map>, <unordered_set>等头文件中。这些容器各有优缺点,适用于不同的场景。下面详细介绍几种主要的容器及其…...
CS144 Lab3 TCPSender复盘
一.基础概念 1.TCPSender在TCPSocket中的地位与作用 Lab0中实现了基于内存模拟的流控制-字节流(ByteStream),底层使用std::deque实现,根据最大容量Capacity进行容量控制。个人理解它相当于应用层的输入输出缓存区,用户…...
建筑可视化中使用云渲染的几大理由
在建筑行业中,可视化技术已成为不可或缺的一部分。无论是设计方案的展示、施工进度的模拟,还是最终效果的呈现,建筑可视化都发挥着至关重要的作用。 建筑可视化是指通过计算机技术和图形学算法,将建筑设计、规划和施工过程中的数据…...
Python数据可视化-地图可视化
1.首先绘制实现数据可视化的思维导图 具体要实现什么功能-怎么处理,先把思路写好 数据来源: 爬取的数据 运行结果: 部分代码: 完整代码请在下方↓↓↓👇获取 转载请注明出处!...
leetcode 动态规划(基础版)单词拆分
题目: 题解: 一种可行的dp做法是基于完全背包问题,将s看成是一个背包,wordDict看作是物品,然后往s中放入物品判断最终是否可以变为给定的s即可。这道题和上一题都用到了在dp如何枚举连续子串和状态表示:枚…...
Ubuntu/Linux调试安装南京来可CAN卡
准备好USB rules文件和can driver文件备用! 必做:放置USB rules文件到对应位置处理权限问题 而后:安装内核driver并编译。需求众多依赖编译环境,视情况安装填补。如GCC,G,make等等 进入对应64bit文件夹中,添加权限,执…...
vue2+TS获取到数据后自动叫号写法
1.父组件写法 初始化: //引入子组件 <odialog ref"odialogRef" onSure"onSurea"></odialog> //子传父private onSurea() {// 初始化信息/重新叫号来的数据this.initTabelData()setTimeout(() > {// 播放声音的数据this.search…...
28、架构-边界:微服务的粒度
微服务的粒度 在设计微服务架构时,确定微服务的粒度是一个关键问题。粒度过大或过小都会带来不同的问题,因此需要找到合理的粒度来划分微服务。下面详细探讨微服务粒度的合理范围及其影响因素。 1. 微服务粒度的上下界 微服务的粒度不应该只有唯一正确…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
