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

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

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

相关文章

C 语言 变量

变量初始值 全局变量&#xff1a;初始值是 0 局部变量&#xff1a;初始值是 随机的 类型限定符 通常不需要显式使用 register 关键字来优化变量的存储和访问。 关键字 _Complex和_Imaginary分别用于表示复数和虚数&#xff08;二者皆是数学概念&#xff09; 变量的声明和定义 c…

逻辑漏洞与越权

逻辑漏洞与越权 越权 如果使用A用户的权限去操作B用户的数据&#xff0c;A的权限小于B的权限&#xff0c;如果能够成功操作&#xff0c;则称之为越权操作。 越权漏洞形成的原因是后台使用了 不合理的权限校验规则导致的。 一般越权漏洞容易出现在权限页面&#xff08;需要登…

因为 postman环境变量全局变量设置好兄弟被公司优化了!

postman环境变量、全局变量设置 在公司中&#xff0c;一般会存在开发环境、测试环境、线上环境等&#xff0c;如果需要在不 同的环境下切换做接口测试&#xff0c;显然我们需要把所有接口的域名进行修改&#xff0c;如果接 口测试用例较多&#xff0c;那么修改会非常费力&…

selenium安装使用详解

安装selenium不少人使用pip命令来安装selenium&#xff0c;辛辛苦苦安装完之后&#xff0c;还是不能使用。所以我们可以是直接使用编译器&#xff0c;pycharm直接安装selenium扩展包。 同时&#xff0c;在这我为大家准备了一份软件测试视频教程&#xff08;含面试、接口、自动…

跨境电商系统搭建 无货源系统对接API 反向代购系统

跨境电商系统是为国外的客户代购中国商品的系统&#xff0c;系统实现与国内电商API对接&#xff0c;客户可直接在系统中搜索国内电商平台的商品。查看演示网站 一级功能二级功能 标准版 高级版 企业版 企业旗舰版 大客户尊享版 标准版高级版企业版企业旗舰版大客户尊享版 前台主…

HarmonyOS创建JavaScript(类 Web开发模式)项目

上文 HarmonyOS带大家创建自己的第一个Page页面并实现路由跳转(ArkTS)带大家创建了我们项目中第一个自己创建的page 并完成了一个跳转逻辑的编写 上文的开发模式是 ArkTS 的 也被称为 声明式开发范式 还有一种 javaScript的 类Web开发模式 这种方式就类似于我们传统的前端开发模…

在线教育培训系统开发:开展线上教育模式

近几年&#xff0c;在线教育发展的非常快&#xff0c;市面上的教育机构通过网络实现了专属的线上教育模式。 与传统的教育学习模式相比&#xff0c;教育培训小程序系统能够为学生和教师带来灵活、便捷、高效的学习方式&#xff0c;也为教育行业带来了创新。随着互联网的发展&a…

一文搞懂全连接算法和它的作用

如果你是搞AI算法的同学&#xff0c;相信你在很多地方都见过全连接层。 无论是处理图片的卷积神经网络&#xff08;CNN&#xff09;&#xff0c;还是处理文本的自然语言处理&#xff08;NLP&#xff09;网络&#xff0c;在网络的结尾做分类的时候&#xff0c;总是会出现一个全…

C语言 扫雷游戏

代码在一个项目里完成&#xff0c;分成三个.c.h文件(game.c,game.h,main.c) 在Clion软件中通过运行调试。 /大概想法/ 主函数main.c里是大框架(菜单,扫雷棋盘初始化&#xff0c;随机函数生成雷&#xff0c;玩家扫雷) game.h函数声明(除main函数和游戏函数外的一些函数声明) ga…

【学习记录】从0开始的Linux学习之旅——字符型设备驱动及应用

一、概述 Linux操作系统通常是基于Linux内核&#xff0c;并结合GNU项目中的工具和应用程序而成。Linux操作系统支持多用户、多任务和多线程&#xff0c;具有强大的网络功能和良好的兼容性。基于前面应用与驱动的开发学习&#xff0c;本文主要讲述如何在linux系统上把应用与驱动…

寒冬不再寒冷:气膜体育馆如何打造温馨运动天地

取暖季即将来临&#xff0c;随着气温逐渐下降&#xff0c;人们在寒冷的冬季里如何保持运动热情和身体的健康成为了一项挑战。而在这个时候&#xff0c;气膜体育馆成为了运动爱好者们的理想场所&#xff0c;提供如春般温暖舒适的运动环境。那么&#xff0c;让我们一起揭秘气膜体…

2023年8月8日 Go生态洞察:Go 1.21 版本发布探索

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

【Java】深入剖析Java枚举类

目录 定义1&#xff09;定义2&#xff09;内部实现3&#xff09;方法与源码 高级特性1&#xff09;switch用法2&#xff09;自定义传值与构造函数3&#xff09;枚举实现抽象方法4&#xff09;枚举注解属性5&#xff09;枚举实现接口 总结 定义 1&#xff09;定义 枚举类是Jav…

Oracle的错误信息帮助:Error Help

今天看手册时&#xff0c;发现上面有个提示&#xff1a; Error messages are now available in Error Help. 点击 View Error Help&#xff0c;显示如下&#xff0c;其实就是oerr命令的图形化版本&#xff1a; 点击Database Error Message Index&#xff0c;以下界面等同于命令…

蒙商出海考察“走出去”“引进来”,探索践行“一带一路”倡议

蒙商新思路&#xff0c;出海正当时&#xff0c;内蒙古自治区促进民营经济发展项目新加坡、马来西亚交流行圆满结束 2023年11月19日-11月25日&#xff0c;内蒙古自治区促进民营经济项目新加坡、马来西亚交流考察行顺利举行&#xff0c;此次出海考察行是自治区发展改革委、工商联…

VBA_MF系列技术资料1-237

MF系列VBA技术资料 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧&#xff0c;我参考大量的资料&#xff0c;并结合自己的经验总结了这份MF系列VBA技术综合资料&#xff0c;而且开放源码&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-04属于定…

Qt开发学习笔记01

设置窗口背景图 在 .h 文件中添加引用和方法 #include <QPainter> #include <QPixmap> void paintEvent(QPaintEvent *);.cpp 文件中实现 paintEvent void sur_dev::paintEvent(QPaintEvent *ev) {QPainter painter(this);QPixmap pix;pix.load(":/image/bj01…

什么是接口测试?这篇文章让你明白!

要成为一名合格的测试工程师&#xff0c;接口测试相关的知识和技能&#xff0c;是不可缺少的。如今&#xff0c;我们随便打开一个大公司的JD&#xff0c;上面基本会要求接口测试经验。 那么&#xff0c;接口测试到底要测些什么&#xff1f; 我相信很多小伙伴跟几年前初入测试…

力扣题:公共前缀/单词-11.18

力扣题-11.18 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;14.最长公共前缀 解题思想&#xff1a;先找到最小的字符串长度&#xff0c;然后进行字符串的遍历即可 class Solution(object):def longestCommonPrefix(self, strs):""&qu…

cookie总结

cookie和session&#xff1a; 一、Cookie和Session二、使用Cookie保存用户上次的访问时间。三、Cookie常用方法总结乱码问题解决&#xff1a; 一、Cookie和Session 会话&#xff1a;用户从打开浏览器到关闭的整个过程就叫1次会话。 比如有的网站登录过一次&#xff0c;下次再进…