C++异常剖析

什么是异常?

        在程序运行的过程中,我们不可能保证我们的程序百分百不出现异常和错误,那么出现异常时该怎么报错,让我们知道是哪个地方错误了呢?
        C++中就提供了异常处理的机制。

一、异常处理的关键字

(1)throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
(2)catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
(3)try:try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块(至少要跟一个)。

        当被try的括号包围的代码块(我们可称之为保护代码)出现异常时,就会抛出异常,catch块的代码就会捕获异常并执行catch包围的代码块。因为异常也可以有不同的种类,所以我们可以在try后面跟着多个catch块,捕获不同的异常,如下:

try
{// 保护代码
}
catch( ExceptionName1 e1 )//第一种异常
{// catch 块
}
catch( ExceptionName2 e2 )//第二种异常
{// catch 块
}
catch( ExceptionName3 eN )//第三种异常
{// catch 块
}

二、捕获异常

        使用 throw 语句可以在代码块中的任何地方抛出异常。
        throw 语句的操作数可以是任意的表达式,表达式的结果的类型决定了抛出的异常的类型。
如下:

        可以看到,我们抛出的是一串字符串,所以编译器报错的信息说异常类型是char(其实是const char*,但它简写了)。

        实际我们编程的时候,我们肯定不希望编译器就只给我说异常类型是char*就完了。我们还希望把它打印出来,让我们看得到"出现了除数为0的错误",这就需要捕获异常。

#include <iostream>
using namespace std;
double division(double a, double b)
{try{if (b == 0){throw "出现了除数为0的错误";//throw关键字抛出错误类型 const char*}}catch (const char* error_string)//捕获const char*类型的错误{cout << error_string << endl;//打印它}return (a / b);
}
int main()
{cout << division(1, 0);
}

        可见,有了try和catch后,程序不会在遇到错误时崩溃终止,而是会处理它,然后继续运行。
所以这个程序依然能输出计算结果inf(无限大),但是在此之前也打印了报错信息。
总之,利用异常处理机制,我们就可以在程序运行时处理异常,大大减少程序崩溃的概率。
你在生活中经常遇到软件闪退的问题,十有八九没有做好异常处理。

三、C++标准库自带的异常类型

下表是对上面层次结构中出现的每个异常的说明:

std::exception 该异常是所有标准 C++ 异常的父类。 std::bad_alloc 该异常可以通过 new 抛出。
std::bad_cast 该异常可以通过 dynamic_cast 抛出。 std::bad_typeid 该异常可以通过 typeid
抛出。 std::bad_exception 这在处理 C++ 程序中无法预期的异常时非常有用。
std::logic_error 理论上可以通过读取代码来检测到的异常。
std::domain_error 当使用了一个无效的数学域时,会抛出该异常。
std::invalid_argument 当使用了无效的参数时,会抛出该异常。
std::length_error 当创建了太长的std::string 时,会抛出该异常。
std::out_of_range 该异常可以通过方法抛出,例如 std::vector 和std::bitset<>::operator。
std::runtime_error 理论上不可以通过读取代码来检测到的异常。
std::overflow_error 当发生数学上溢时,会抛出该异常。
std::range_error 当尝试存储超出范围的值时,会抛出该异常。
std::underflow_error 当发生数学下溢时,会抛出该异常。

四、异常规格说明

异常规格说明的目的是为了让函数使用者知道该函数可能抛出那些异常,可以再函数的声明中列出这个函数可能抛出的所有异常类型,例如:

viod fun() throw(A,B,C,D);

        throw后面的括号内,必须写出会抛出的异常的类型,如果括号里面是空的,说明这个函数不会抛出任何异常。
        如果你不声明throw(A,B,C,D),那么编译器就会认为这个函数什么异常都可能会抛出。
        异常规范声明可以让编译器知道可能会抛出的异常有哪些,就可以提升编译速度和给编译器更多的优化空间,让你的代码性能更高,也可以让其他程序员了解你这段代码可能会产生的异常,提高代码可读性。

五、noexcept关键字

在C++11中新增了noexcept关键字以表示这个函数不会抛出某种异常。并且可以阻止异常的传播。

无条件的noexcept关键字

当我们声明的noexcept关键字无条件时,表示这个函数中所的所有代码都不会产生异常,如下:

void fun() noexcept; //C++11
void fun() noexcept(); //也可以写成这样,等价的
void fun() noexcept(...); //也可以写成这样,等价的
void fun() noexcept(true); //也可以写成这样,等价的
有条件的noexcept关键字
void fun(Type& x, Type& y) noexcept(noexcept(noexcept(fun1()),noexcept(fun2()));
//表示fun函数内会调用到的fun1函数和fun2函数都不会抛出异常,但不保证其他代码不会抛出异常

什么时候我们需要noexcept关键字?
        使用noexcept表明函数或操作不会发生异常,会给编译器更大的优化空间。然而,并不是加上noexcept就能提高效率。
以下情形鼓励使用noexcept:

(1)移动构造函数(move constructor)
(2)移动分配函数(move assignment)
(3)析构函数(destructor)。这里提一句,在新版本的编译器中,析构函数是默认加上关键字noexcept的。下面代码可以检测编译器是否给析构函数加上关键字noexcept。
(4)叶子函数(Leaf Function)。叶子函数是指在函数内部不分配栈空间,也不调用其它函数,也不存储非易失性寄存器,也不处理异常。
最后强调一句,在不是以上情况或者没把握的情况下,不要轻易使用noexcept。

六、定义新的异常类型

只有C++标准库自带的异常类型肯定是不够用的,我们实际工作中还需要根据项目需求定义新的异常类型。

#include <iostream>
#include <exception>
using namespace std;
class DivisionZeroException :public exception//基于exception类定义新的异常类型除以0导致的异常类
{
public://这里重载了父类的虚函数what()//throw ()的括号里面没有东西,这表示这个函数不会抛出任何异常//const 是常量的关键字,常量在定义后无法被修改const char* what() const throw (){return "出现了除以0的错误\n";}
};
double division(double a, double b)
{try{if (b == 0){DivisionZeroException e;throw e;//throw关键字抛出错误类型DivisionZeroException}}catch (DivisionZeroException e)//捕获const char*类型的错误{cout<<e.what();//打印什么异常了}return (a / b);
}
int main()
{cout << division(1, 0);
}
出现了除数为0的错误
inf

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

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

相关文章

联想电脑重装系统Win10步骤和详细教程

联想电脑拥有强大的性能&#xff0c;很多用户办公都喜欢用联想电脑。有使用联想电脑的用户反映系统出现问题了&#xff0c;想重新安装一个正常的系统&#xff0c;但是不知道重新系统的具体步骤。接下来小编详细介绍给联想电脑重新安装Win10系统系统的方法步骤。 推荐下载 系统之…

客厅颜值担当:木饰面电视背景墙设计。福州中宅装饰,福州装修

你是否也为客厅的装修设计而烦恼&#xff1f;现在&#xff0c;我为你带来一款高颜值的木饰面电视背景墙设计&#xff0c;它将是你客厅的亮点所在。 1️⃣ 确定背景墙的尺寸和位置 首先&#xff0c;你需要确定背景墙的尺寸和位置&#xff0c;这取决于你家电视的大小和放置位置。…

重新认识Word——多级列表和项目符号

重新认识Word——多级列表和项目符号 多级列表没有运用标题样式但标题格式统一 正式公本文书项目符号和自动编号项目符号自动编号软回车重新起头开始编号解决编号与文本距离过大问题 之前我们重新认识了Word里面的样式&#xff0c;现在的情况就是&#xff0c;我的一些文字已经运…

Python Authlib库:构建安全可靠的身份验证系统

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在现代应用程序中&#xff0c;安全性是至关重要的&#xff0c;特别是在处理用户身份验证时。Authlib库为Python开发者提供了一套强大的工具&#xff0c;用于简化和增强身份验证和授权流程。本文将深入探讨Authli…

因小失大,一个普通的postman多接口顺序执行,让项目瘫痪了一天

Runner的使用 postman不仅可以单独运行某个接口&#xff0c;postman的 Runner模块可以运行多个接口&#xff0c;可以实现真正意义上的自动化接口测试 Runner的主要功能如下 按顺序调用接口&#xff0c;执行用例&#xff1b; 批量发送请求&#xff1b; 对接口数据进行参数化…

vuepress-----15、md用法进阶

vuepress markdown说明文档 https://www.vuepress.cn/guide/markdown.html # 示例&#xff1a;封装countUp.js为Vue组件 https://github.com/inorganik/countUp.js https://inorganik.github.io/countUp.js/ # 安装 yarn add countup.js# 创建vue文件 全局Vue组件存放位置…

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之文件管理(1)》(22)

《Linux操作系统原理分析之文件管理&#xff08;1&#xff09;》&#xff08;22&#xff09; 7 文件管理7.1 文件与文件系统7.1.1 文件7.1.3 文件系统及其功能 7.2 文件的组织结构7.2.1 文件的逻辑结构7.2.2 文件的物理结构一、顺序结构&#xff08;顺序文件或连续文件&#xf…

Java来实现二叉树算法,将一个二叉树左右倒置(左右孩子节点互换)

文章目录 二叉树算法二叉树左右变换数据 今天来和大家谈谈常用的二叉树算法 二叉树算法 二叉树左右变换数据 举个例子&#xff1a; Java来实现二叉树算法&#xff0c;将一个二叉树左右倒置&#xff08;左右孩子节点互换&#xff09;如下图所示 实现的代码如下&#xff1a;以…

ECharts的颜色渐变

目录 一、直接配置参数实现颜色渐变 二、使用ECharts自带的方法实现颜色渐变 一、两种渐变的实现方法 1、直接配置参数实现颜色渐变 横向的渐变&#xff1a; //主要代码 option {xAxis: {type: category,boundaryGap: false,data: [Mon, Tue, Wed, Thu, Fri, Sat, Sun]},yA…

云上巴蜀丨云轴科技ZStack成功实践精选(川渝)

巴蜀——古政权必争之地 不仅拥有优越的战略位置 而且拥有丰富的自然资源&#xff0c;悠久的历史文化 如今的川渝经济、人口发展迅速 2023年前三季度&#xff0c;四川与重庆GDP增速均超过国家平均线&#xff0c;为6.5%为5.6% 川渝经济发展带动数字化发展浪潮 云轴科技ZSt…

打造专属小程序,乔拓云模板平台助力商家抢占先机

打造专属小程序&#xff0c;乔拓云模板平台助力商家抢占先机&#xff01;该平台涵盖全行业小程序模板&#xff0c;一键复制即可上线。 想要快速创建高效实用的小程序&#xff0c;乔拓云小程序模板开发平台为您提供了解决方案&#xff01;我们为您提供一系列精心设计的小程序模板…

LeetCode Hot100 131.分割回文串

题目&#xff1a; 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 方法&#xff1a;灵神-子集型回溯 假设每对相邻字符之间有个逗号&#xff0c;那么就看…

[c++]—string类___深度学习string标准库成员函数与非成员函数(string的增删查改函数)

沉淀,沉淀,再沉淀. &#x1f469;&#x1f3fb;‍&#x1f4bb;作者:chlorine &#x1f449;上一篇&#xff1a;string标准库成员函数和非成员函数(上) 目录 &#x1f36d;构造和析构的实现 &#x1f36d; string→c类型的字符串数组 &#x1f36d;operator[]类对象元素的访…

c语言-动态内存管理

文章目录 一、为什么会有动态内存管理二、申请内存函数1、malloc2、free3、calloc4、realloc 三、常见的动态内存的错误四、练习 一、为什么会有动态内存管理 1.我们一般的开辟空间方式&#xff1a; int a 0;//申请4个字节空间 int arr[10] { 0 };//申请40个字节空间2.这样…

解决在Linux中进行redis的主从复制时出现的从机可以获取到主机的信息,主机获取不到从机的信息~

主机&#xff1a; 从机1&#xff1a; 从机2&#xff1a; 出现上述的原因是我在redis.conf中设置了密码&#xff0c;那么就导致了我在进行主从复制时&#xff0c;需要进行密码验证&#xff0c;然后我在网上查阅了很多资料&#xff0c;有的说让在从机中指定密码&#xff0c;有的说…

一对多聊天室

多人聊天包 由于要先创建服务面板&#xff0c;接收客户端连接的信息&#xff0c;此代码使用顺序为先启动服务端&#xff0c;在启动客户端&#xff0c;服务端不用关&#xff0c;不然会报错。多运行几次客户端&#xff0c;实现单人聊天 创建服务面板 package yiduiduo;import j…

【头歌系统数据库实验】实验7 SQL的复杂多表查询-1

目录 第1关&#xff1a;求各颜色零件的平均重量 第2关&#xff1a;求北京和天津供应商的总个数 第3关&#xff1a;求各供应商供应的零件总数 第4关&#xff1a;求各供应商供应给各工程的零件总数 第5关&#xff1a;求重量大于所有零件平均重量的零件名称 第6关&#xff1…

初识人工智能,一文读懂人工智能概论(1)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

Python Django-allauth: 构建全面的用户身份验证系统

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Django-allauth是一个功能强大的Django插件&#xff0c;旨在简化和定制Web应用程序中的用户身份验证和管理。本文将深入介绍Django-allauth的核心功能、基本用法以及实际应用场景&#xff0c;通过丰富的示例代码…