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

news2025/1/16 6:04:22
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.coloradmin.cn/o/1623170.html

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

相关文章

C++ | Leetcode C++题解之第41题缺失的第一个正数

题目&#xff1a; 题解&#xff1a; class Solution { public:int firstMissingPositive(vector<int>& nums) {int n nums.size();for (int i 0; i < n; i) {while (nums[i] > 0 && nums[i] < n && nums[nums[i] - 1] ! nums[i]) {swap(…

助力实现更可持续未来的智能解决方案:AI如何改变世界

人工智能已然成为今年的热门话题。由于生成式AI应用的快速采用&#xff0c;新闻头条充斥着有关AI如何彻底改变我们的政策制定、就业和经济走向的预测。您知道AI也是我们应对各种可持续发展挑战的先锋吗&#xff1f;AI通过分析大量数据&#xff0c;并提供有用的见解和工具&#…

Python | Leetcode Python题解之第44题通配符匹配

题目&#xff1a; 题解&#xff1a; class Solution:def isMatch(self, s: str, p: str) -> bool:def allStars(st: str, left: int, right: int) -> bool:return all(st[i] * for i in range(left, right))def charMatch(u: str, v: str) -> bool:return u v or v…

半波整流220V转正5V负-5V100mA恒压WT5101A

半波整流220V转正5V负-5V100mA恒压WT5101A WT5101A 是一款专为 Buck 和 Buck-Boost 拓扑而设计的高效、具有成本优势的离线恒压稳压器&#xff0c;内嵌有500V MOSFET。在降低系统成本的同时&#xff0c;这款稳压器只需少量的外部元件就能输出默认的5V电压。在轻负载条件下&…

30kw 直流回馈老化测试负载箱的优点

直流回馈老化测试负载箱是一种专门用于对电源设备进行老化测试的设备&#xff0c;其主要优点如下&#xff1a; 直流回馈老化测试负载箱采用了先进的直流回馈技术&#xff0c;能够将测试过程中产生的电能回馈到电网中&#xff0c;大大提高了能源的利用效率。这种技术不仅能够节…

水电气能耗管理云平台

安科瑞薛瑶瑶18701709087/17343930412 能耗管理云平台采用泛在物联、云计算、大数据、移动通讯、智能传感器等技术手段可为用户提供能源数据采集、统计分析、能效分析、用能预警、设备管理等服务&#xff0c;平台可以广泛应用于多种领域。

微信小程序按钮点击时的样式hover-class=“hover“

小程序的button组件很好用&#xff0c;按钮点击的时候会显示点击状态&#xff0c;默认的就是颜色加深 但是我们改变了button的背景色之后&#xff0c;就看不出点击效果了&#xff0c;解决起来也很简单 关键代码就是小程序的 hover-class 属性&#xff0c;需要注意的是&#xff…

【java】27:java绘图

坐标体系 - 介绍&#xff1a; 下图说明了Java坐标系。坐标原点位于左上角&#xff0c;以像素为单位。在Java坐标系中&#xff0c;第一个是x坐标&#xff0c;表示当前位置为水平方向&#xff0c;距离坐标原点个像素&#xff1b;第二个是y坐标&#xff0c;表示当前位置为垂直方向…

APP自动化测试-Android SDK SDK Manager.exe或者uiautomatorviewer.bat打不开,点击就一闪而已的原因

原因是找不到Java.exe的路径&#xff0c; 如果是uiautomatorviewer.bat打不开&#xff0c;则使用文本编辑器打开它&#xff0c;然后添加java安装路径 set java_exeC:\Program Files\Java\jdk1.8.0_321\bin\java.exe 同理&#xff1a; 如果是SDK Manager.exe和AVD Manager.ex…

2024全新Java学习路线图一条龙(视频+课件+源码资料)

前言 互联网浩瀚无际,你能来到这里,是机遇也是缘分,机遇,就像我的标题一样,你找到了一份Java 360度无死角的 Java 学习路线,而缘分让我们相遇,注定给你的学习之路搭上一把手,送你一程。 整条线路除了拥有后端整个技术体系外,还涵盖了前端、大数据、云计算、运维等各…

【telnet 命令安装】centos8 linux下安装telnet命令

在CentOS 8上安装Telnet服务&#xff0c;您需要分别安装Telnet客户端和服务器端。以下是安装步骤的概述&#xff1a; 检查是否已安装Telnet&#xff1a; 您可以使用rpm命令来检查系统是否已经安装了Telnet客户端或服务器端。例如&#xff1a; rpm -qa | grep telnet-client rpm…

OWASP发布十大开源软件安全风险及应对指南

​ 最近爆发的XZ后门事件&#xff0c;尽管未酿成Log4j那样的灾难性后果&#xff0c;但它再次敲响了警钟&#xff1a;软件供应链严重依赖开源软件&#xff0c;导致现代数字生态系统极其脆弱。面对层出不穷的安全漏洞&#xff0c;我们需要关注开源软件 (OSS)风险 &#xff0c;改进…

Web前端笔记1.0【Html详解,CSS详解】【Js待完善】

Web前端 html5 html5是构建web前端内容的一种语言描述方式 标签 标签分类 单标签&#xff1a;<input type text"> 双标签语法规范&#xff1a;<标签名> <标签名> 内容 </标签名></标签名> (可相互嵌套&#xff09; 常用标签 标题标…

在不使用PageHelper或Mybatis的情况下实现手动分页

有些特殊情况下我们不需要查库但前端数据需要分页&#xff0c;我们就需要手写分页实现&#xff0c;比如在线用户的功能我们可能会去Redis中查有哪些用户&#xff0c;然后返回给前端&#xff0c;但前端需要分页处理&#xff0c;我们就需要实现手动分页&#xff0c;话不多说直接上…

超越边界:如何ChatGPT 3.5、GPT-4、DALL·E 3和Midjourney共同重塑创意产业

KKAI&#xff08;kkai人工智能&#xff09;是一个整合了多种尖端人工智能技术的多功能助手平台&#xff0c;融合了OpenAI开发的ChatGPT3.5、GPT4.0以及DALLE 3&#xff0c;并包括了独立的图像生成AI—Midjourney。以下是这些技术的详细介绍&#xff1a; **ChatGPT3.5**&#xf…

vue 请求php接口 header 传自定义参数 提示cors 跨域问题

前端地址 http://192.168.0.125:4021 请求后端地址的时候报 from origin http://192.168.0.125:4021 has been blocked by CORS policy: Request header field userid is not allowed by Access-Control-Allow-Headers in preflight response. 大概意思是请求 header里有个…

递归算法/斐波那契数列

目录 递归 直接递归 间接递归 思想沿用 斐波那契数列 图片来源网络&#xff0c;侵权联系可删 递归 递归&#xff08;Recursion&#xff09;是一种编程技术&#xff0c;其中函数或方法直接或间接地调用自身。递归通常用于解决可以分解为更小、更简单的子问题的问题。递归的…

抗D盾是什么,为什么游戏被攻击了需要抗D盾

游戏行业DDoS攻击的主要原因是因为游戏产品生命周期偏短&#xff0c;而DDoS供给成本又不高&#xff0c;只要发起攻击&#xff0c;企业为确保游戏稳定运营而不得不快速做出让步&#xff0c;致使敲诈勒索的成功率相对更高。在遭受DDoS攻击后&#xff0c;游戏公司的日损失甚至多达…

[Flutter3] 记录Dio的简单封装(一)

文章目录 效果使用ResponseEntity类DioManager封装_onResponse / _onDioException 的设计Response的处理catch处理 效果 请求成功/失败/异常的日志输出效果 成功: 失败:500 失败:404 网络异常: 使用 举个使用的例子, 在调用 DioManager的时候, 直接通过返回值的状态, 来…

世强硬创获昕感科技授权代理,SiC MOSFET实现超低导通电阻

近日&#xff0c;世强先进&#xff08;深圳&#xff09;科技股份有限公司&#xff08;下称“世强先进”&#xff09;获北京昕感科技有限责任公司&#xff08;下称“昕感科技”&#xff0c;英文名&#xff1a;NEXIC&#xff09;授权代理&#xff0c;为光伏、储能、电网、新能源汽…