异常处理【C++提升】(基本思想,重要概念,异常处理的函数机制、异常机制,栈解旋......你想要的全都有)

 更多精彩内容.....

🎉❤️播主の主页✨😘

Stark、-CSDN博客

本文所在专栏:

C系列语法知识_Stark、的博客-CSDN博客

座右铭:梦想是一盏明灯,照亮我们前行的路,无论风雨多大,我们都要坚持不懈。


异常是一种程序控制机制,与函数机制独立和互补:函数是一种以栈结构展开的上下函数衔接的程序控制系统,异常是另一种控制结构,它依附于栈结构,却可以同时设置多个异常类型作为网捕条件,从而以类型匹配在栈机制中跳跃回馈

异常设计目的:栈机制是一种高度节律性控制机制,面向对象编程却要求对象之间有方向、有目的的控制传动,从一开始,异常就是冲着改变程序控制结构,以适应面向对象程序更有效地工作这个主题,而不是仅为了进行错误处理。

异常设计出来之后,却发现在错误处理方面获得了最大的好处。处理错误的这个过程就是抛异常。


一、异常处理的基本思想

传统的异常处理机制是C语言使用的通过函数返回值来获取错误信息然后通过if等条件语句处理这些发生的错误。

异常处理的基本思想

1)C++的异常处理机制使得异常的引发异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计对不同类型异常的处理。

2)异常是专门针对抽象编程中的一系列错误处理的,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,如图

 

3)异常超脱于函数机制,决定了其对函数的跨越式回跳。

4)异常跨越函数


二、异常处理的实现方法

C++中的异常处理是通过trycatchthrow关键字来实现的。它允许程序在运行时处理错误,使得程序的控制流可以在出现异常时更优雅地转移。下面是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::exceptionstd::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()输出错误。

 六、标准程序库异常


感谢观看,希望对你有所帮助!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

828华为云征文|华为云Flexus云服务器X实例搭建部署H5美妆护肤分销商城、前端uniapp

准备国庆之际&#xff0c;客户要搭个 H5 商城系统&#xff0c;这系统好不容易开发好啦&#xff0c;就差选个合适的服务器上线。那可真是挑花了眼&#xff0c;不知道哪款性价比高呀&#xff01;就像在琳琅满目的选择前。最终慧眼识珠&#xff0c;选择了华为云 Flexus X。至于为什…

redis高级篇 抢红包案例的设计以及分布式锁

一 抢红包案例 1.1 抢红包 二倍均值算法&#xff1a; M为剩余金额&#xff1b;N为剩余人数&#xff0c;公式如下&#xff1a; 每次抢到金额随机区间&#xff08;0&#xff0c;&#xff08;M/N&#xff09;*2&#xff09; 这个公式&#xff0c;保证了每次获取的金额平均值…

TX-LCN框架 分布式事务

一、三种事务模式 1&#xff09;LCN 基于XA协议&#xff0c;事务提交或回滚的操作由事务管理服务器统一告诉它管理的多个项目&#xff0c;也就是说在A事务&#xff0c;B事务的事务提交操作或回滚操作都是在同一时刻发生&#xff0c;并且要么都提交&#xff0c;要么都回滚。 LCN…

低代码可视化-UniApp二维码可视化-代码生成器

市面上提供了各种各样的二维码组件&#xff0c;做了一简单的uniapp二维码组件&#xff0c;二维码实现依赖davidshimjs/qrcodejs。 组件特点 跨浏览器支持&#xff1a;利用Canvas元素实现二维码的跨浏览器兼容性&#xff0c;兼容微信小程序、h5、app。 无依赖性&#xff1a;QR…

数据库(MySQL):使用命令从零开始在Navicat创建一个数据库及其数据表(一).创建基础表

一. 使用工具和命令 1.1 使用的工具 Navicat Premium 17 &#xff1a;“Navicat”是一套可创建多个连接的数据库管理工具。 MySQL版本8.0.39 。 1.2 使用的命令 Navicat中使用的命令 命令命令解释SHOW DATABASES&#xff1b;展示所有的数据库CREATE DATABASE 数据库名称; 创…

震动传感器介绍及实战

目录 前言 震动传感器 1.震动传感器配图 2.震动传感器原理图 3.震动传感器使用 1-震动传感器的意义 2-震动传感器的应用场景 3- SW-18010P震动传感器使用方法 震动传感器控制灯 操作 增加延时 使用SPC-ISP生成演示函数 总结 前言 我们上节已经简单了解了LED的使用…

【机器学习】音乐生成——AI如何创作个性化音乐与配乐

我的主页&#xff1a;2的n次方_ 音乐是人类文化的重要组成部分&#xff0c;它具有极强的情感表达和艺术价值。近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;AI已经能够自动生成音乐&#xff0c;甚至根据用户需求创作个性化配乐。AI生成音乐的应用场景广泛&…

redis中的数据类型(Set与ZSet)

&#xff08;一&#xff09;set set在我们目前有两个意思&#xff0c;首先就是这里使用的集合&#xff0c;第二个是我们的set和get方法 因为set是一个集合&#xff0c;所以他具有集合的一些特点&#xff1a; 1.集合中的元素无序 2.集合中的元素是不可重复的 3.集合间是可…

5G NR物理信号

文章目录 NR 物理信号与LTE的区别上行参考信号DMRS (UL)SRSPT-RS(UL) 下行参考信号DMRS(DL)PT-RS(DL)CSI-RSPSSSSS NR 物理信号与LTE的区别 用SSS、CSI-RS和DMRS 取代了CRS信号。下行业务信道采用TM1波束赋形传输模式。基于SSB 或者CSI-RS进行RSRP和SINR测量。基于DMRS 进行共…

【Mybatis篇】Mybatis的关联映射详细代码带练 (多对多查询、Mybatis缓存机制)

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【计算机网络】,【Mybatis篇】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 目录 &#x1f3af;一.关联映射概述 &#x1f6a…

2024.9.29 问卷数据分析

最近拿到了一份受众回访的问卷数据&#xff0c;排到的任务是对它进行数据探索。 其实对于问卷数据的处理我只在参加正大杯那次做过&#xff08;正大杯拿了校三&#xff09;&#xff0c;可见这个处理水平还有待提高&#xff08;当然是各种原因促成的结果&#xff09;&#xff0…

17 链表——21. 合并两个有序链表 ★

17 链表 21. 合并两个有序链表 将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1: 输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4] 算法设计: 合并两个有序链表,并保持有序性,可以采用迭代法和递归法两种…

卸载WSL(Ubuntu),卸载linux

禁用 WSL 功能 打开 Windows 功能&#xff1a; 按下 Windows R 打开运行对话框&#xff0c;输入 optionalfeatures&#xff0c;然后按回车。 禁用 WSL&#xff1a; 在弹出的 Windows 功能窗口中&#xff0c;找到 适用于 Linux 的 Windows 子系统&#xff08;Windows Subsystem…

Windows环境 源码编译 FFmpeg

记录一下windows环境纯代码编译ffmeg的过程&#xff01; 目录 一、安装MSYS2 1.下载安装 2.配置 3.修改源 4.测试与更新 二、安装其他必要工具 1.安装MinGW-w64 2.安装git 3..安装make等工具 4.编译前的其他准备工作 ①.重命名link.exe ②.下载和安装YASM ③.安装…

Docker 从安装到实战

Docker 是一个开源的平台&#xff0c;用于自动化应用程序的部署、扩展和管理。它利用操作系统级别的虚拟化&#xff0c;将应用程序及其依赖项封装在称为容器的轻量级、可移植的单元中。以下是 Docker 的一些关键特点&#xff1a; 容器化&#xff1a;Docker 容器可以在任何支持 …

用CSS创造三角形案例

6.3.2 用CSS创造三角形 用div来创建&#xff0c;角上是平分的&#xff0c;所以要是内部宽高为0&#xff0c;其他边透明&#xff0c;正好是三角形。 代码 div {border: 12px solid;width: 0;height: 0;border-color: transparent red transparent transparent; } 与伪元素aft…

vscode+stfp插件,实现远程自动同步文件代码

概述 远程同步代码&#xff0c;将本地代码实时保存到同一局域网内的另一台电脑&#xff08;linux系统&#xff09;&#xff0c;这里的本地代码也可以是远程服务上的代码&#xff0c;即从一个远程ip同步到另一台远程ip服务器。 工具 vscode&#xff0c;SFTP插件 安装 vscod…

【重学 MySQL】五十、添加数据

【重学 MySQL】五十、添加数据 使用INSERT INTO语句添加数据基本语法示例插入多行数据注意事项 使用LOAD DATA INFILE语句批量添加数据其他插入数据的方式注意事项 在MySQL中&#xff0c;添加数据是数据库操作中的基本操作之一。 使用INSERT INTO语句添加数据 使用 INSERT IN…

突发!Meta重磅发布Movie Gen入局视频生成赛道!

引言 Meta于2024年10月4日首次推出 Meta Movie Gen&#xff0c;号称是迄今为止最先进的媒体基础模型。Movie Gen 由 Meta 的 AI 研究团队开发&#xff0c;在一系列功能上获取最先进的效果&#xff0c;包括&#xff1a;文生视频、创建个性化视频、精准的视频编辑和音频创作。 …

libcrypto.so.10内容丢失导致sshd无法运行

说明: 我的是centos的服务器,被扫出有ssh漏洞,需要升级到OpenSSH_9.8p1, OpenSSL 3.0.14 4 报错 我的系统和环境升级前的版本 这是升级之后的版本 OpenSSH_9.8p1, OpenSSL 3.0.14 4 解决:我这个的原因是升级的时候把这个文件给删除了, 复制旧服务器上的 libcrypto.so.1…