异常处理【C++提升】(基本思想,重要概念,异常处理的函数机制、异常机制,栈解旋......你想要的全都有)
更多精彩内容.....
🎉❤️播主の主页✨😘
Stark、-CSDN博客
本文所在专栏:
C系列语法知识_Stark、的博客-CSDN博客
座右铭:梦想是一盏明灯,照亮我们前行的路,无论风雨多大,我们都要坚持不懈。
异常是一种程序控制机制,与函数机制独立和互补:函数是一种以栈结构展开的上下函数衔接的程序控制系统,异常是另一种控制结构,它依附于栈结构,却可以同时设置多个异常类型作为网捕条件,从而以类型匹配在栈机制中跳跃回馈。
异常设计目的:栈机制是一种高度节律性控制机制,面向对象编程却要求对象之间有方向、有目的的控制传动,从一开始,异常就是冲着改变程序控制结构,以适应面向对象程序更有效地工作这个主题,而不是仅为了进行错误处理。
异常设计出来之后,却发现在错误处理方面获得了最大的好处。处理错误的这个过程就是抛异常。
一、异常处理的基本思想
传统的异常处理机制是C语言使用的通过函数返回值来获取错误信息然后通过if等条件语句处理这些发生的错误。

1)C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计对不同类型异常的处理。
2)异常是专门针对抽象编程中的一系列错误处理的,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,如图
3)异常超脱于函数机制,决定了其对函数的跨越式回跳。
4)异常跨越函数
二、异常处理的实现方法
C++中的异常处理是通过try
、catch
和throw
关键字来实现的。它允许程序在运行时处理错误,使得程序的控制流可以在出现异常时更优雅地转移。下面是C++异常处理的基本结构和使用示例:
try:用于包裹可能会抛出异常的代码。
catch:用于捕获异常并处理它。
throw:用于抛出一个异常。
#include <iostream>
#include <stdexcept> void riskyFunction() { // 随机抛出一个异常 throw std::runtime_error("发生了一个运行时错误");
} int main() { try { riskyFunction(); } catch (const std::runtime_error& e) { std::cerr << "捕获到异常: " << e.what() << std::endl; } catch (...) { std::cerr << "捕获到未知异常" << std::endl; } std::cout << "程序继续运行..." << std::endl; return 0;
}
riskyFunction
: 这是一个声明的函数,故意抛出一个std::runtime_error
异常。try
块:在这里放置调用可能抛出异常的函数。catch
块:捕获特定类型的异常,并执行相应的处理。在这个示例中,我们捕获std::runtime_error
类型的异常。e.what()
: 这是std::runtime_error
类中的一个方法,返回错误消息。
1) 若有异常则通过throw操作创建一个异常对象并抛掷。
2) 将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句,然后执行try块内的保护段。
3) 如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句继续执行下去。
4) catch子句按其在try块后出现的顺序被检查。匹配的catch子句将捕获并处理异常(或继续抛掷异常)。
5) 如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序。
6)处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上扔。
三、异常处理的重要概念
异常的类型:可以抛出不同类型的异常,通常使用标准库中的异常类(如std::exception
、std::runtime_error
等)。
捕获多个异常:可以使用多个catch
块捕获不同类型的异常。
未知异常:使用catch (...)
来捕获所有未被捕获的异常类型。
异常安全:设计函数时要考虑异常的影响,确保在发生异常时可以保持程序的状态一致性。
异常传播:如果在一个函数中抛出异常而没有捕获它,则异常会被传播到调用该函数的代码层次。
自定义异常:可以通过继承std::exception
类定义自己的异常类型。
#include <iostream>
#include <exception> class MyException : public std::exception {
public: const char* what() const noexcept override { return "这是一个自定义异常"; }
}; void myFunction() { throw MyException();
} int main() { try { myFunction(); } catch (const MyException& e) { std::cerr << "捕获到自定义异常: " << e.what() << std::endl; } return 0;
}
这段代码展示了如何定义和使用自定义的异常类型。在实际开发中,使用异常处理机制可以提高程序的健壮性和可读性。
四、异常处理的机制分析
①经典案例:被零整除
int divide(int x, int y )
{if (y ==0){throw x;}return x/y;
}int main()
{try{cout << "8/2 = " << divide(8, 2) << endl;cout << "10/0 =" << divide(10, 0) << endl;}catch (int e){cout << "e" << " is divided by zero!" << endl;}catch(...){cout << "未知异常" << endl;}cout << "ok" << endl;system("pause");return 0;
}
②异常:函数机制
class A{};
void f(){if(...) throw A;
}
void g(){try{f();}catch(B){cout<<“exception B\n”;}
}
int main(){g();return 0;
}
throw A将穿透函数f,g和main,抵达系统的最后一道防线——激发terminate函数.该函数调用引起运行终止的abort函数.最后一道防线的函数可以由程序员设置.从而规定其终止前的行为.
修改系统默认行为:
1).可以通过set_terminate函数修改捕捉不住异常的默认处理器,从而使得发生捉不住异常时,被自定义函数处理:
2).void myTerminate(){cout<<“HereIsMyTerminate\n”;}
3).set_terminate(myTerminate);
4).set_terminate函数在头文件exception中声明,参数为函数指针void(*)().
③异常:异常机制
构造函数没有返回类型,无法通过返回值来报告运行状态,所以只通过一种非函数机制的途径,即异常机制,来解决构造函数的出错问题。
异常机制与函数机制互不干涉,但捕捉的方式是基于类型匹配。捕捉相当于函数返回类型的匹配,而不是函数参数的匹配,所以捕捉不用考虑一个抛掷中的多种数据类型匹配问题
class A{};
class B{};int main()
{try{int j = 0; double d = 2.3; char str[20] = "Hello";cout<<"Please input a exception number: ";int a; cin>>a;switch(a){case 1: throw d; case 2: throw j; case 3: throw str;case 4: throw A(); case 5: throw B();default: cout<<"No throws here.\n"; }}catch(int){cout<<"int exception.\n";}catch(double){cout<<"double exception.\n";}catch(char*){cout<<"char* exception.\n";}catch(A){cout<<"class A exception.\n";}catch(B){cout<<"class B exception.\n";}cout<<"That's ok.\n";system("pause");
}
Tips:catch代码块必须出现在try后,并且在try块后可以出现多个catch代码块,以捕捉各种不同类型的抛掷。
异常机制是基于这样的原理:程序运行实质上是数据实体在做一些操作,因此发生异常现象的地方,一定是某个实体出了差错,该实体所对应的数据类型便作为抛掷和捕捉的依据。
异常捕捉严格按照类型匹配:异常捕捉的类型匹配之苛刻程度可以和模板的类型匹配媲美,它不允许相容类型的隐式转换,比如,抛掷char类型用int型就捕捉不到.例如下列代码不会输出“int exception.”,从而也不会输出“That’s ok.” 因为出现异常后提示退出。
④栈解旋
异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反。这一过程称为栈的解旋(unwinding)。
class MyException {};
class Test
{
public:Test(int a=0, int b=0){this->a = a;this->b = b;cout << "Test 构造函数执行" << "a:" << a << " b: " << b << endl;}void printT(){cout << "a:" << a << " b: " << b << endl;}~Test(){cout << "Test 析构函数执行" << "a:" << a << " b: " << b << endl;}
private:int a;int b;
};void myFunc() throw (MyException)
{Test t1;Test t2;cout << "定义了两个栈变量,异常抛出后测试栈变量的如何被析构" << endl;throw MyException();
}void main()
{//异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,//都会被自动析构。析构的顺序与构造的顺序相反。//这一过程称为栈的解旋(unwinding)try {myFunc();}//catch(MyException &e) //这里不能访问异常对象catch(MyException ) //这里不能访问异常对象{cout << "接收到MyException类型异常" << endl;}catch(...){cout << "未知类型异常" << endl;}system("pause");return ;
}
⑤异常:接口声明
1)为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型,例如:
void func() throw (A, B, C , D); //这个函数func()能够且只能抛出类型A B C D及其子类型的异常。
2)如果在函数声明中没有包含异常接口声明,则次函数可以抛掷任何类型的异常,例如:
void func();
3)一个不抛掷任何类型异常的函数可以声明为:
void func() throw();
4) 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用terminate函数中止程序。
⑥异常类型和异常变量的生命周期
1)throw的异常是有类型的,可以使,数字、字符串、类对象。
2)throw的异常是有类型的,catch严格按照类型进行匹配。
3)注意 异常对象的内存模型 。
五、异常的层次结构
⚪异常是类 – 创建自己的异常类
⚪异常派生
⚪异常中的数据:数据成员
⚪按引用传递异常
(继承在异常中的应用) 在异常中使用虚函数
案例:设计一个数组类 MyArray,重载[]操作,
数组初始化时,对数组的个数进行有效检查
1)index<0 抛出异常eNegative
2)index = 0 抛出异常 eZero
3)index>1000抛出异常eTooBig
4)index<10 抛出异常eTooSmall
5)eSize类是以上类的父类,实现有参数构造、并定义virtual void printErr()输出错误。
六、标准程序库异常
感谢观看,希望对你有所帮助!
相关文章:

异常处理【C++提升】(基本思想,重要概念,异常处理的函数机制、异常机制,栈解旋......你想要的全都有)
更多精彩内容..... 🎉❤️播主の主页✨😘 Stark、-CSDN博客 本文所在专栏: C系列语法知识_Stark、的博客-CSDN博客 座右铭:梦想是一盏明灯,照亮我们前行的路,无论风雨多大,我们都要坚持不懈。 异…...

基于springboot vue 电影推荐系统
博主介绍:专注于Java(springboot ssm 等开发框架) vue .net php python(flask Django) 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设,从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找…...

八、特殊类型异常机制
特殊类型&异常机制 数据类型枚举类型匿名类、单例类和伴生对象匿名类单例类伴生对象 委托模式密封类型异常机制异常的使用异常的处理 数据类型 对于那些只需要保存数据的类型,我们常常需要为其重写toString、equals等函数,针对于这种情况下…...
虾皮Shopee Android面试题及参考答案
HTTP 状态码有哪些? HTTP 状态码是用以表示网页服务器超文本传输协议响应状态的 3 位数字代码。主要分为五大类: 1xx 信息性状态码:表示服务器正在处理请求,这些状态码是临时的响应,主要用于告诉客户端请求已经被接收,正在处理中。例如,100 Continue 表示客户端应当继续…...
Docker Compose 部署大模型GPU集群:高效分配与管理算力资源
Docker Compose 部署大模型GPU集群:高效分配与管理算力资源 文章目录 Docker Compose 部署大模型GPU集群:高效分配与管理算力资源一 Dockerfile 编写二 Dockerfile 示例三 分配GPU资源1)GPU分配:指定count2)GPU分配&am…...

直立行走机器人技术概述
直立行走机器人技术作为现代机器人领域的重要分支,结合了机械工程、计算机科学、人工智能、传感技术和动态控制等领域的最新研究成果。随着技术的不断发展,直立行走机器人在救灾、医疗、家庭辅助等领域开始发挥重要作用。本文旨在对直立行走机器人的相关…...
【Linux】wsl虚拟机时间和实际时间不符合
本文首发于 ❄️慕雪的寒舍 偶然遇到了这个问题,触发原因是电脑在开启wsl的情况下进入了 休眠 模式,且在无网络情况下几天不使用。 然后开启wsl,发现git log显示最新commit的提交时间是明天,给我吓一跳,然后才发现原来…...

初识算法 · 滑动窗口(1)
目录 前言: 长度最小的子数组 题目解析 算法原理 算法编写 无重复长度的最小字符串 题目解析 算法原理 算法编写 前言: 本文开始,介绍的是滑动窗口算法类型的题目,滑动窗口本质上其实也是双指针,但是呢&#…...

nginx和gateway的关系和区别
在技术选型时,选择 Nginx 和 Spring Cloud Gateway(或简称为 Gateway)主要取决于具体应用场景和技术需求。下面是两者的一些关键差异和适用场景。 一、Nginx 概念 Nginx 是一个高性能的 Web 服务器和反向代理服务器,常被用作静…...

【算法笔记】滑动窗口算法原理深度剖析
【算法笔记】滑动窗口算法原理深度剖析 🔥个人主页:大白的编程日记 🔥专栏:算法笔记 文章目录 【算法笔记】滑动窗口算法原理深度剖析前言一.长度最小的子数组1.1题目1.2思路分析1.3算法流程1.4正确性证明1.5代码实现 二.无重复…...

4S店4S店客户管理系统小程序(lw+演示+源码+运行)
社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非…...
rabbitMq------连接管理模块
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言管理的字段连接内存管理对象 前言 我们的网络通信框架使用的muduo库,而在mudu库中是已经有了连接的概念,但是我们呢还有一个信道的概念…...
【部署项目】禹神:前端项目部署上线笔记
1.项目打包 ● 我们开发用的脚手架其实就是一个微型服务器,用于:支撑开发环境、运行代理服务器等。 ● 打包完的文件中不存在:.vue、.jsx、.less 等文件,而是:html、css、js等。 ● 打包后的文件,不再借助…...
力扣10.1
983. 最低票价 在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行。在接下来的一年里,你要旅行的日子将以一个名为 days 的数组给出。每一项是一个从 1 到 365 的整数。 火车票有 三种不同的销售方式 : 一张 为期一天 的通行证售…...

TypeScript 算法手册 - 【冒泡排序】
文章目录 TypeScript 算法手册 - 冒泡排序1. 冒泡排序简介1.1 冒泡排序定义1.2 冒泡排序特点 2. 冒泡排序步骤过程拆解2.1 比较相邻元素2.2 交换元素2.3 重复过程 3. 冒泡排序的优化3.1 提前退出3.2 记录最后交换位置案例代码和动态图 4. 冒泡排序的优点5. 冒泡排序的缺点总结 …...

计算机网络——http和web
无状态服务器——不维护客户端 怎么变成有状态连接 所以此时本地建立代理—— 若本地缓存了——但是服务器变了——怎么办?...

使用 Light Chaser 进行大屏数据可视化
引言 在当今数据驱动的世界中,数据可视化变得越来越重要。Light Chaser 是一款基于 React 技术栈的大屏数据可视化设计工具,通过简单的拖拽操作,你可以快速生成漂亮、美观的数据可视化大屏和看板。本文将介绍如何使用 Light Chaser 进行数据…...
Java中的异常概念
在Java编程中,异常(Exception)是一种特殊的情况,它在程序执行期间发生,会干扰程序正常的流程。 ## 一、异常的产生原因 1. **用户输入错误** - 例如,当一个程序期望用户输入一个整数,而用户…...
flutter_鸿蒙next_Dart基础②List
目录 代码示例 代码逐段解析 1. 创建和打印列表 2. 强类型列表 3. 创建可扩展的空列表 4. 创建填充列表 5. 列表扩展 6. 使用可选展开操作符 7. 获取列表长度 8. 列表反转 9. 添加多个元素 10. 移除元素 11. 根据索引移除元素 12. 在特定位置插入元素 13. 清空列…...
【2024保研经验帖】武汉大学测绘遥感国家重点实验室夏令营(计算机向)
前言 先说本人背景:末211,rk前5%,无科研,有几个竞赛(数模、机器人等) 武大的国重是我参加的第二个夏令营,武大国重这次有提前开几个分会场,一个在中南大学,一个在吉林大学,还有在兰…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...