C++高级特性:异常概念与处理机制(十四)

1、异常的基本概念
  • 异常:是指在程序运行的过程中发生的一些异常事件(如:除数为0,数组下标越界,栈溢出,访问非法内存等)

  • C++的异常机制相比C语言的异常处理:

    • 函数的返回值可以忽略,但异常不可以忽略(忽略异常程序会结束)
    • 整型返回值没有任何语义信息,而异常却包含语义信息,有时从类名中就能体现出来
    try{
        throw 异常值;
    } catch (异常类型1 异常值1) {
    
    } catch (异常类型2 异常值2) {
    
    } catch (异常类型3 异常值3) {
    
    } catch (...){      // 任何异常都可以捕获
    	
    }
    
2、异常使用
  • 抛出异常位置后面的代码将没有机会执行,并且跳转到对应的捕获函数进行捕获
  • 通过不同类型的异常捕获进行处理,对于没有适合的捕获将会走默认的任意异常捕获
  • 如果没有任意异常捕获,并且向外抛出知道main也没有处理,那么程序将会直接结束!
2.1、异常的抛出与捕获
void test1()
{
    try {
//         throw 1;								// 
//        throw 'a';
        throw 3.14f;
    } catch (int e) {
        std::cout << "int 异常值为: " << e << std::endl;
    } catch (char e){
        std::cout << "char 异常值为: " << e << std::endl;
    } catch (...){
        std::cout << "默认异常处理" << std::endl;
    }
}
2.2、栈解旋

异常被抛出后,从进入try块起到异常抛出前(throw),这期间在栈上创建的所有对象都会被自动析构。析构的顺序与构造的顺序相反,这一过程被称为栈解旋。

void test2()
{
    try {
        A a1(10);
        A a2(20);
        A a3(30);
        throw 1;
        A a4(40);
    } catch (int e){
        std::cout << "int 异常值为: " << e << std::endl;
    } catch (char e){
        std::cout << "char 异常值为: " << e << std::endl;
    } catch (...){
        std::cout << "默认异常处理" << std::endl;
    }
    std::cout << "------------------" << std::endl;
}
/*
A(), m = 10
A(), m = 20
A(), m = 30
~A(), m = 30
~A(), m = 20
~A(), m = 10
int 异常值为: 1
------------------
*/
3、异常的接口声明
  • 异常的接口声明描述一个函数可以抛出哪些类型的异常
  • 为什么要抛出异常:有时候当前代码中不希望看到任何的异常处理,当遇到异常时向外抛出,并集中处理
3.1、函数默认

函数声明时不指定任何异常信息的描述,表示可以抛出任何异常

void test3()
{
//    throw 1;
//    throw 'a';
    throw "string";
}
3.2、抛出指定类型异常
  • 被指定只能抛出int和char类型的异常,抛出其他类型的异常将无法捕获
  • 但这种具体化可能抛出异常的类型写法在C++17中被移除了,C++17中推荐不写或者写noexcept(false)表示可能有异常抛出。
void func4() throw(int, char)    // noexcept(false)
{
    throw "hello";
}
void test4()
{
    try {
        func4();
    } catch (int e){
        std::cout << "int 异常值为: " << e << std::endl;
    } catch (char e){
        std::cout << "char 异常值为: " << e << std::endl;
    } catch (const char * e){
        std::cout << "string 异常值为: " << e << std::endl;
    } catch (...){
        std::cout << "默认异常处理" << std::endl;
    }
    std::cout << "------------------" << std::endl;
}
/*
terminate called after throwing an instance of 'char const*'
*/
3.3、不抛出任何异常
  • throw()表示不抛出任何异常,但是函数体内依然可以继续抛出,然而即使抛出外部捕获也无法处理
  • C++11之后推荐使用noexcept表示不抛出任何异常
void func5() throw()		// noexcept
{
    throw 1;
}
void test5()
{
    try {
        func5();
    } catch (int e){
        std::cout << "int 异常值为: " << e << std::endl;
    } catch (char e){
        std::cout << "char 异常值为: " << e << std::endl;
    } catch (const char * e){
        std::cout << "string 异常值为: " << e << std::endl;
    } catch (...){
        std::cout << "默认异常处理" << std::endl;
    }
    std::cout << "------------------" << std::endl;
}
/*
terminate called after throwing an instance of 'int'
*/
4、异常变量的生命周期
class MyException{
public:
    MyException(){
        std::cout << "异常变量构造函数" << std::endl;
    }
    MyException(const MyException& myException){
        std::cout << "拷贝构造函数" << std::endl;
    }
    ~MyException(){
        std::cout << "析构函数" << std::endl;
    }
};
4.1、抛出普通变量异常

抛出普通变量异常会发生拷贝构造,可能会导致一部分的性能丢失

void Life_test1()
{
    try{
        throw MyException{};
    } catch (MyException e){
        std::cout << "----------" << std::endl;
    }
}
/*
异常变量构造函数
拷贝构造函数
----------
析构函数
析构函数
*/
4.2、抛出指针类型异常

抛出指针类型异常需要注意释放对象的内存空间,长期不释放会导致堆区空间告急

void Life_test2()
{
    try{
        throw new MyException();
    } catch (MyException* e){
        std::cout << "----------" << std::endl;
        delete e;
    }
}
/*
异常变量构造函数
----------
析构函数
*/
4.3、抛出引用类型异常

推荐使用抛出引用类型的异常处理,不会进行拷贝和手动分配堆区空间的问题,不会造成内存泄漏和性能负担

void Life_test3()
{
    try{
        throw MyException();
    } catch (MyException& e){
        std::cout << "----------" << std::endl;
    }
}
/*
异常变量构造函数
----------
析构函数
*/
5、异常的多态
  • 实际开发中应该会对所有的异常进行封装处理,不然catch语句太多太多无法处理,代码狮山

  • 这种情况就可以考虑使用多态的特性了,定义基类异常,所有可能的异常都继承基类异常,而捕获时只需要捕获基类异常即可

class BaseException{
public:
    virtual void printException(){
        std::cout << "BaseException" << std::endl;
    }
};

class NullPointerException: public BaseException{
public:
    virtual void printException(){
        std::cout << "空指针异常!" << std::endl;
    }
};

class OutOfRangeException: public BaseException{
public:
    virtual void printException(){
        std::cout << "越界访问异常!" << std::endl;
    }
};

void polymorphism_exception_test1()
{
    try {
//        throw NullPointerException();                 // 输出: 空指针异常!
        throw OutOfRangeException();                    // 输出: 越界访问异常!
    } catch (BaseException& baseException){
        baseException.printException();
    }
}
6、C++标准异常

在这里插入图片描述

异常名称描述
exception所有标准异常的父类
bad_alloc当operator new和operator new[]请求分配内存失败时的异常
bad_exception这是个特殊的影响,如果函数的异常抛出列表里声明了bad_exception异常,当函数内部抛出了异常列表中没有的异常,这时调用的unexpected函数中若抛出异常,不论什么类型都会被替换为bad_exception类型
bad_typeid使用typeid操作符获取一个nullptr指针的类型,这时抛出bad_typeid异常
bad_cast使用dynamic_cast转换引用失败的时抛出
ios_base::failureio操作过程中出现错误
logic_error逻辑错误,可以在运行前检测的错误
runtime_error运行时错误,仅在运行时才可以检测的错误

logic_error子类

异常名称描述
length_error试图生成一个超过该类型最大长度的对象是,例如vector的resize操作
domain_error参数的阈值错误,主要用在数学函数中。例如使用一个负值调用只能操作非负数的函数
out_of_range超出有效范围
invalid_argument参数不合适。标准库中,当利用一个非’0’和’1’的string对象构造bitset时抛出这个异常

runtime_error子类

异常名称描述
range_error计算结果超出了有意义的值域范围
overflow_error算术计算上溢出
underflow_error算数计算下溢出
void standard_exception_test1()
{
    try {
        throw std::out_of_range("我越界了, 哈哈哈!");
//        throw std::bad_alloc();                         // 输出:std::bad_alloc
//        throw std::bad_cast();                          // 输出:std::bad_cast
    } catch (std::exception& e){
        std::cout << e.what() << std::endl;             // 我越界了, 哈哈哈!
    }
}
6.1、继承标准异常抛出
  • 这个函数在继承重写时需要加入noexcept或者对应的宏,防止子类异常抛出前被父类提前抛出
  • const表示这个函数只能读不能改
  • 当标准异常无法满足开发需求时,可以通过继承基类异常来编写自己的异常进行抛出,这样接口就统一了。
class NewException: public std::exception{
private:
    std::string msg;
public:
    NewException() :msg("我异常了!"){

    }
    explicit NewException(const std::string &msg) : msg(msg) {

    }

    virtual const char *what() const noexcept override {				// 需要加入noexcept
        return msg.c_str();
    }

    ~NewException() {

    }
};

void standard_exception_test2()
{
    try {
        throw NewException();
    } catch (std::exception& e){
        std::cout << e.what() << std::endl;									// 输出:我异常了!
    }
}

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

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

相关文章

麒麟龙芯loongarch64 electron 打包deb包

在麒麟龙芯&#xff08;loongarch64&#xff09;电脑上 使用electron 开发桌面应用。之前用electron-packager 打包出来的是文件夹 是 unpack 包。现在需要打包deb包&#xff0c;依据开发指南开始打包。 在项目文件夹下 打开终端 输入 npm run packager 先打包unpack包 然后…

FreeRTOS:3.消息队列

FreeRTOS消息队列 本文主要基于消息队列的源码进行分析&#xff0c;来对FreeRTOS的消息队列进一步学习。 消息队列非常重要&#xff0c;因为后面的各种信号量基本都是基于队列的&#xff0c;搞清楚消息队列的源码&#xff0c;也就搞清楚消息队列的原理。 参考链接&#xff1…

188页 | 2023企业数字化转型建设方案(数据中台、业务中台、AI中台)(免费下载)

1、知识星球下载&#xff1a; 如需下载完整PPTX可编辑源文件&#xff0c;请前往星球获取&#xff1a;https://t.zsxq.com/19KcxSeyA 2、免费领取步骤&#xff1a; 【1】关注公众号 方案驿站 【2】私信发送 【2023企业数字化转型建设方案】 【3】获取本方案PDF下载链接&#…

AI:165-Coze自定义赛博风格Bot-图片生成操作指南

Coze是由字节跳动推出的一个AI聊天机器人和应用程序编辑开发平台&#xff0c;旨在帮助用户快速创建各种类型的聊天机器人、智能体、AI应用和插件&#xff0c;并将其部署在社交平台和即时聊天应用程序中&#xff0c;如Discord、WhatsApp、Twitter、飞书、微信公众号等。 这个平…

计算机网络3——数据链路层3以太网的MAC层

文章目录 一、MAC 层的硬件地址1、介绍2、注意点3、定制标准 二、MAC 帧的格式1、结构2、工作原理3、其他 一、MAC 层的硬件地址 1、介绍 在局域网中&#xff0c;硬件地址又称为物理地址或 MAC地址(因为这种地址用在MAC帧中)。 大家知道&#xff0c;在所有计算机系统的设计中…

剑指Offer题目笔记32(拓扑排序)

面试题113&#xff1a; 解决方案&#xff1a; 将课程看成图中的节点&#xff0c;如果两门课程存在先修顺序那么它们在图中对应的节点之间存在一条从先修课程到后修课程的边&#xff0c;因此这是一个有向图。可行的修课序列实际上是图的拓扑排序序列。图中的每条边都是从先修课…

C++并发编程

基本介绍 线程 C98标准没有直接提供原生的多线程支持 在C98中&#xff0c;并没有像后来的C11标准中那样的<thread>库或其他直接的多线程工具 然而&#xff0c;这并不意味着在C98中无法实现多线程。开发者通常会使用平台特定的API&#xff08;如Windows的线程API或POSI…

前端开发攻略---用原生JS在网页中也能实现 文本转语音!

1、原理 语音合成 (也被称作是文本转为语音&#xff0c;英语简写是 tts) 包括接收 app 中需要语音合成的文本&#xff0c;再在设备麦克风播放出来这两个过程。 Web API中对此有一个主要控制接口 SpeechSynthesis&#xff0c;外加一些处理如何表示要被合成的文本 (也被称为 utte…

玩转微服务-SonarQube

这里写目录标题 第一节 SonarQube1.1 简介1.2 四个组成部分1.2.1 SonarQube服务器1.2.2 SonarQube数据库1.2.3 插件1.2.4 Scanner 1.3 工作流程 第二节 SonarQube的安装2.1 安装2.2 插件 第三节 P3C规范3.1 简介3.2 SonarQube 配置 P3C规范3.3 IDEA配置 P3C规范 第四节 Maven项…

机器学习-期末复习

本文的内容按照作者的课程考试要求书写&#xff0c;仅供复习参考。&#x1f337;&#x1f337;&#x1f337;欢迎大家指正&#xff01; 机器学习是一种人工智能&#xff08;AI&#xff09;的分支领域&#xff0c;它致力于开发能够通过数据学习和改进的算法和模型。简而言之&…

2024年AIGC+教育行业报告

在宏观层面上&#xff0c;如果把人工智能看作一种生命体&#xff0c;AIGC教育的内涵其实是碳基生命和硅基生命的 交互和培育问题。AIGC技术是对人脑计算、思考、判断等内在能力的延伸&#xff0c;是人的智能在机器形态 上的规模化聚集、运作和反应。由此&#xff0c;部分基础性…

【漏洞复现】云时空社会化商业ERP系统LoginName SQL注入漏洞

漏洞描述&#xff1a; 云时空社会化商业ERP系统loginName存在SQL注入漏洞&#xff0c;攻击者可以通过此漏洞获取数据库敏感信息。 搜索语法: Fofa-Query: app"云时空社会化商业ERP系统" 漏洞详情&#xff1a; 1.云时空社会化商业ERP系统。 2.漏洞POC&#xff1a…

倒计时开始!Big Demo Day第十二期,揭秘DePIN,探索Web3未来(附参会指南)

香港—— 全球领先的 Web3.0 活动 Big Demo Day 第十二期即将于 4 月 26 日在香港数码港盛大举行。本次活动由知名科技企业 ZeeprLabs 赞助&#xff0c;Central Research 主办&#xff0c;并得到 Techub News 的联合主办以及数码港、852Web3 等机构的合作支持。 在过去的 11 期…

鸿蒙HarmonyOS应用 - ArkUI组件

ArkUI组件 基础组件 Image 声明Image组件并设置图片源 网络权限&#xff1a;ohos.permission.INTERNET Image(scr: string | PixelMap | Resource)// 1. string&#xff1a;用于加载网络图片&#xff0c;需要申请网络权限 Image("https://xxx.png")// 2. PixelMap…

驱鸟器低成本OTP语音方案选型-wtn6020唯创知音

一、开发背景&#xff1a; 随着农业现代化的不断推进&#xff0c;鸟类对农作物的侵扰问题愈发严重。传统的驱鸟方法&#xff0c;如人工驱赶或使用化学药剂&#xff0c;不仅效率低下&#xff0c;而且可能对环境造成污染。因此&#xff0c;开发一种高效、环保、低成本的驱鸟器成…

考研日常记录(upd 24.4.24)

由于实在太无聊了 &#xff0c; 所以记录以下考研备考日常 &#xff0c; 增加一点成就感 &#xff0c; 获得一点前进动力。 文章目录 2024.4.18 周四课程情况&#xff1a;时间规划&#xff1a; 2024.4.19 周五课程情况&#xff1a;时间规划&#xff1a; 2024.4.20 周六2024.4.2…

RK3588构建ubuntu22.04根文件系统

前言 RK系列的平台提供了buildroot和debian的系统&#xff0c;使用脚本可以直接构建出来&#xff0c;但是没有提供ubuntu的系统&#xff0c;很多厂商只提供一个rootfs.img的固件包&#xff0c;没有将方法开源出来。本文实现了从ubuntu官网开始构建一个ubuntu22.04根文件系统。…

SSTV音频转图片

SSTV工具有很多&#xff0c;这里使用RX-SSTV慢扫描工具 下载安装 RX-SSTV解码软件 下载地址&#xff1a;https://www.qsl.net/on6mu/rxsstv.htm 一直点下一步&#xff0c;安装成功如下图: 虚拟声卡e2eSoft 由于SSTV工具是根据音频传递图片信息&#xff0c;正常解法需要一…

人耳的七个效应

1、掩蔽效应 • 人们在安静环境中能够分辨出轻微的声音&#xff0c;即人耳对这个声音的听域很低&#xff0c;但在嘈杂的环境中轻微的声音就会被淹没掉&#xff0c;这时将轻微的声音增强才能听到。 • 这种在聆听时&#xff0c;一个声音的听阈因另一声音的出现而提高的现象&…

本地修改localhost--手把手

找到本地hosts文件 1、C:\Windows\System32\drivers–快捷键ctrlR,输入drivers 2、点击etc目录&#xff0c;找到hosts文件&#xff0c;右键使用记事本方式打开编辑 3、添加自己想得到的域名【只能在本地使用】 127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com 127.0.0.…
最新文章