C++进阶--异常

news/2024/9/19 6:25:07/ 标签: c++, java, servlet

C语言传统的处理方式

  1. 终止程序:在发生错误时直接终止程序的运行,可以通过assert宏来进行实现。如assert(condition),其中condition不满足要求时,将会使程序立刻停止执行,并输出相关错误信息。这种方式的确定是用户很难接受突然的程序终止,它没有提供任何机会来进行修复和处理
  2. 返回错误码:在函数体内,如果发生错误,将错误码作为函数的返回值进行返回。通常情况下0表示返回成功,非零值表示错误,并且根据对应返回值做出相应的处理。

这些方式在实际应用中对代码的可读性和可维护性是非常低的,尤其在大型项目中。

C++异常的概念

在 C++ 中,异常是指程序在运行过程中遇到的一些意外情况或错误,导致当前代码无法正常执行下去的情况。这些异常可能是由于程序逻辑错误、外部环境变化或者运行时错误引起的。

异常处理机制允许程序员在代码中标识出可能引发异常的代码块,并提供一种机制来捕获和处理这些异常,以便程序在出现问题时能够以一种更加优雅和可控的方式来处理异常情况,而不至于导致程序崩溃或者无法正常执行。

在 C++ 中,异常处理的主要机制包括以下几个关键组件:

  1. 抛出异常(Throwing Exceptions):当程序遇到错误或异常情况时,可以使用 throw 关键字来抛出一个异常。异常可以是任何类型的数据,但通常是标准库中的异常类或者自定义的异常类的实例。

  2. 捕获异常(Catching Exceptions):在代码中使用 try 块来标识可能会引发异常的代码段,然后使用 catch 块来捕获和处理这些异常。catch 块可以指定捕获的异常类型,以及对应的处理逻辑。

  3. 异常传递(Exception Propagation):如果在 try 块中的代码抛出了异常,程序会在当前函数中查找匹配的 catch 块来处理异常。如果找不到匹配的 catch 块,则异常会在当前函数中被终止,并且会将异常传递给调用栈上的上一层函数,继续寻找匹配的 catch 块。

  4. 清理资源(Resource Cleanup):在异常处理过程中,可以使用 finally 块来执行一些清理工作,确保资源在程序终止时得到正确释放。

使用异常处理机制可以使程序的错误处理逻辑更加清晰和灵活,提高了程序的健壮性和可维护性。

异常的使用

异常的抛出和匹配规则

异常的抛出和匹配规则是异常处理机制的核心。
异常抛出和匹配规则的基本概念:

  1. 异常的抛出(Throwing Exceptions)

    • 异常可以由 throw 关键字抛出。抛出异常时,可以使用任何类型的表达式,通常是一个异常对象的实例,例如:
      throw std::runtime_error("Something went wrong");
      
    • 抛出的异常可以是任何类型,包括标准库提供的异常类型,或者用户自定义的异常类的实例。
  2. 异常的匹配(Exception Matching)

    • 异常的匹配是指在 try 块中捕获并处理异常的过程。
    • try 块中的代码抛出异常时,程序会在 try 块后面的 catch 块中寻找与抛出的异常类型相匹配的处理程序。
    • catch 块可以使用异常类型来指定要捕获的异常。如果抛出的异常的类型与 catch 块中指定的类型匹配,那么相应的 catch 块就会执行。
    • 异常类型可以是异常类的实例、指针、引用或者任何继承自 std::exception 的类型。
  3. 异常的传递(Exception Propagation)

    • 如果在 try 块中的代码抛出异常,程序会在当前函数中查找匹配的 catch 块来处理异常。
    • 如果当前函数中没有匹配的 catch 块,那么异常会传播到调用当前函数的函数中,依此类推,直到找到匹配的 catch 块为止。
    • 如果在调用栈上找不到匹配的 catch 块,程序会调用 std::terminate() 来终止程序的执行。

简单使用

double Division(int a, int b)
{// 当b == 0时抛出异常if (b == 0)throw "Division by zero condition!";elsereturn ((double)a / (double)b);
}
void Func()
{int len, time;cin >> len >> time;cout << Division(len, time) << endl;cout << "=====================" << endl;}int main()
{try {Func();}catch (const char* errmsg){cout << errmsg << endl;}return 0;
}

在这里插入图片描述

异常的缺陷

double Division(int a, int b)
{// 当b == 0时抛出异常if (b == 0)throw "Division by zero condition!";elsereturn ((double)a / (double)b);
}void fxx()
{int i = 0;cin >> i;if (i % 2 == 0){throw 1;}
}void Func()
{int len, time;cin >> len >> time;cout << Division(len, time) << endl;try{fxx();}catch (int x){cout <<__LINE__<<"捕获异常:" << x << endl;}cout << "=====================" << endl;}int main()
{try {Func();}catch (const char* errmsg){cout << errmsg << endl;}catch (int x){cout << __LINE__ <<"捕获异常:"<< x << endl;}cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;return 0;
}

在这里插入图片描述

异常安全

异常安全是指程序在面对异常时依然能够保持系统的一致性和稳定性,不会导致资源泄漏或数据损坏。异常安全性分为三个级别:

  1. 基本异常安全(Basic Exception Safety):即使发生异常,程序的内部状态不会被破坏。程序能够保证在异常抛出前的状态与异常抛出后的状态之间存在一种合理的约束关系。例如,内存不会泄漏,对象不会处于不一致的状态。

  2. 强异常安全(Strong Exception Safety):即使发生异常,程序的内部状态也不会改变。程序能够保证在异常抛出前的状态与异常抛出后的状态完全一致。这意味着所有操作要么成功完成,要么没有执行任何修改。通常需要使用事务性或回滚操作来实现。

  3. 无异常安全(No-Throw Guarantee):程序不会抛出任何异常。这意味着所有的操作都能够在不引发异常的情况下成功完成。通常用于对性能和可靠性要求极高的系统,例如实时系统。

实现异常安全的方法通常包括以下几种:

  • 使用 RAII(资源获取即初始化)技术,通过对象的生命周期来管理资源,确保在对象销毁时资源得到正确释放
  • 在异常发生时使用异常处理机制来回滚操作,恢复到先前的状态。
  • 使用事务性操作来确保操作的原子性,当发生异常时可以回滚整个操作。
  • 使用智能指针、容器等标准库提供的异常安全的工具和数据结构,减少手动管理资源的复杂度。

未知异常

一般来说,如果我们不确定哪个地方会出现错误,我们可以增加一个捕获模块:用来显示未知的异常情况

double Division(int a, int b)
{// 当b == 0时抛出异常if (b == 0)throw "Division by zero condition!";elsereturn ((double)a / (double)b);
}void fxx()
{int i = 0;cin >> i;if (i % 2 == 0){throw 10;}
}void Func()
{int len, time;cin >> len >> time;cout << Division(len, time) << endl;fxx();
}int main()
{try{Func();}catch (const char* errmsg){cout << errmsg << endl;}catch (const string& err){cout << err << endl;}catch (...) // 任意类型的异常{cout << "未知异常" << endl;}return 0;
}

在这里插入图片描述

异常继承体系

这里,将模拟一般情况异常抛出的情况,利用多态的原理来捕获对应哪个流程的异常。

class Exception
{
public:Exception(const string& errmsg, int id):_errmsg(errmsg), _id(id){}virtual string what() const{return _errmsg;}protected:string _errmsg;  // 错误描述int _id;         // 错误编号
};// 继承和多态
class SqlException : public Exception
{
public:SqlException(const string& errmsg, int id, const string& sql):Exception(errmsg, id), _sql(sql){}virtual string what() const{string str = "SqlException:";str += _errmsg;str += "->";str += _sql;return str;}
private:const string _sql;
};class CacheException : public Exception
{
public:CacheException(const string& errmsg, int id):Exception(errmsg, id){}virtual string what() const{string str = "CacheException:";str += _errmsg;return str;}
};class HttpServerException : public Exception
{
public:HttpServerException(const string& errmsg, int id, const string& type):Exception(errmsg, id), _type(type){}virtual string what() const{string str = "HttpServerException:";str += _type;str += ":";str += _errmsg;return str;}
private:const string _type;
};void SQLMgr()
{srand(time(0));if (rand() % 7 == 0){throw SqlException("权限不足", 100, "select * from name = '张三'");}cout << "!!!!!!!!!!!!!!!!!!!!!!!!运行成功" << endl;
}void CacheMgr()
{srand(time(0));if (rand() % 5 == 0){throw CacheException("权限不足", 100);}else if (rand() % 6 == 0){throw CacheException("数据不存在", 101);}SQLMgr();
}void HttpServer()
{srand(time(0));if (rand() % 3 == 0){throw HttpServerException("请求资源不存在", 100, "get");}else if (rand() % 4 == 0){throw HttpServerException("权限不足", 101, "post");}CacheMgr();
}int main()
{srand(time(0));// 20:15继续while (1){Sleep(1000);try {HttpServer(); // io}catch (const Exception& e) // 这里捕获父类对象就可以{// 多态cout << e.what() << endl;}catch (...){cout << "Unkown Exception" << endl;}}return 0;
}

在这里插入图片描述


http://www.ppmy.cn/news/1433527.html

相关文章

计算机网络4——网络层1

文章目录 一、网络层1、概念2、网络层的两个层面1&#xff09;介绍2&#xff09;问题3&#xff09;解决 二、网际协议IP1、介绍2、虚拟互联网络1&#xff09;介绍2&#xff09;案例 3、IP地址1&#xff09;IP 地址及其表示方法2&#xff09;分类的IP地址3&#xff09;无分类编址…

视频滚动字幕一键批量轻松添加,解锁高效字幕编辑,提升视频质量与观众体验

视频已成为我们获取信息、娱乐休闲的重要渠道。一部成功的视频作品&#xff0c;除了画面精美、音质清晰外&#xff0c;字幕的添加也是至关重要的一环。字幕不仅能增强视频的观感&#xff0c;还能提升信息的传达效率&#xff0c;让观众在享受视觉盛宴的同时&#xff0c;更加深入…

探究C++20协程(5)——基于挂起实现无阻塞的定时器

实现目标 当用传统的线程 sleep 函数来让程序等待时&#xff0c;实际上是在阻塞当前线程。阻塞意味着这个线程在指定的时间&#xff08;例如100毫秒&#xff09;内无法执行任何其他任务。这种方式虽然简单&#xff0c;但效率低下&#xff0c;因为它导致CPU资源在等待期间未被充…

使用uni-app开发app时遇到mqtt.js不可用的问题

使用uni-app开发app时遇到mqtt.js不可用的问题 1 问题背景 基于 Vue3 版本创建了 uni-app 项目用于开发微信小程序&#xff0c;项目中用到了 mqtt.js&#xff08;v4.1.0&#xff09;&#xff0c;编译为微信小程序能够正常运行&#xff0c;但是编译为 APP 后&#xff0c;控制台…

C# winform OpenProtocol中数据中的UI是什么类型?

C# winform OpenProtocol中数据中的UI是什么类型&#xff1f;

Nginx安装withSSL模块

Nginx安装withSSL模块 Nginx 配置文件&#xff0c;开启ssl访问时&#xff0c;报出错误信息&#xff1a; nginx: [emerg] the “ssl” parameter requires ngx_http_ssl_module in /usr/local/nginx/conf/nginx_proxy.mimvp.com.conf:76 原因分析: nginx缺少http_ssl_module…

Unity系统学习笔记

文章目录 1.基础组件的认识1.0.组件继承关系图1.1.项目工程文件结构&#xff0c;各个文件夹都是做什么的&#xff1f;1.2.物体变化组件1.2.3.三维向量表示方向1.2.4.移动物体位置附录&#xff1a;使用变换组件实现物体WASD移动 1.3.游戏物体和组件的显示和禁用1.3.1.界面上的操…

数据结构 - 顺序表实现通讯录

test.c文件 #define _CRT_SECURE_NO_WARNINGS 1#include "Contact.h" int main() {Con myContacts;ConInit(&myContacts);int choice;int index;char targetName[100];PerInfo contact; // 创建一个新的联系人信息实例while (1) {printf("\n--- 通讯录管理…

PaddleSeg (2) 模型训练

已处理好数据集和配置文件,可以开始模型训练。 启动训练 python tools/train.py --config configs/xxx.yml --do_eval --use_vdl --save_interval 500 --save_dir output/xxx上述训练命令解释:* `--config`

java spring 07 createBean()和doCreateBean()

01.createBean方法 protected Object createBean(String beanName, RootBeanDefinition mbd, Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean " beanName "");}RootBea…

引导过程和服务控制

1、Linux系统开机引导过程 1&#xff09;开机自检 检测硬件设备&#xff0c;找到能够引导系统的设备&#xff0c;比如硬盘 2&#xff09;MBR引导 运行MBR扇区里的主引导程序GRUB 3&#xff09;启动GRUB菜单 系统读取GRUB配置文件(/boot/grub2/grub.cfg)获取内…

spring boot 定义启动页 到 login

当前办法只是针对 项目启动后 直接跳转到 指定静态页面 如果有验证身份 安全等问题 可以另外想办法 去添加 &#xff0c;需要的直接 拉过去使用 修改 【"redirect: 需要启动后访问到文件位置得地址 ”】 直接上代码 &#xff1a; import org.springframework.context…

【教程】使用vitepress搭配githubPages构建自己的在线笔记

1. 创建VitePress项目 确保自己已经安装好了node&#xff0c;我这个笔记用的是node 18.16.0, 怎么安装nvm这个可以csdn或者掘金&#xff0c;再或者等我有空了我就更新一下 使用nvm安装node # 查看可用版本 nvm list avaliable # 安装node nvm install 18.16.0 # 切换node nvm …

(C语言)sscanf 与 sprintf详解

目录 1.sprintf函数详解 2. sscanf函数详解 1.sprintf函数详解 头文件&#xff1a;stdio.h 作用&#xff1a;将格式化的数据写入字符串里&#xff0c;也就是将格式化的数据转变为字符串。 演示&#xff1a; #include <stdio.h> struct S {char name[10];int height;…

无人机探测技术,无人机侦测频谱仪技术实现详解

频谱仪&#xff0c;又称为频谱分析仪&#xff0c;是一种用于测量电信号频谱特性的仪器。其基本原理是通过将时域信号转换为频域信号&#xff0c;进而分析信号的频率成分、功率分布、谐波失真等参数。频谱仪利用快速傅里叶变换&#xff08;FFT&#xff09;算法&#xff0c;将采集…

Github 2024-04-24 C开源项目日报 Top9

根据Github Trendings的统计,今日(2024-04-24统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目9C++项目1我的电视 - 安卓电视直播软件 创建周期:40 天开发语言:CStar数量:649 个Fork数量:124 次关注人数:649 人贡献人数:1 人Open…

STM32 USB HID报告描述符没有报告长度

STM32 USB HID设置(STM32CubeMX)_我也想成大侠的博客-CSDN博客 不影响鼠标功能

面向对象设计模式

设计模式通常被分为三种类型&#xff1a;创建型模式、结构型模式和行为型模式。 创建型模式 创建型模式主要关注对象的创建机制&#xff0c;它们提供了一种将对象创建和实例化的机制&#xff0c;使得系统在不直接依赖于具体类的情况下能够灵活地创建对象。 创建型模式的典型…

力扣---填充每个节点的下一个右侧节点指针 II

给定一个二叉树&#xff1a; struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 NULL 。 初始状态下&#xff0c;所有 next 指针都…

Prompt Engineering,提示工程

什么是提示工程&#xff1f; 提示工程也叫【指令工程】。 Prompt发送给大模型的指令。比如[讲个笑话]、[用Python编个贪吃蛇游戏]、[给男/女朋友写情书]等看起来简单&#xff0c;但上手简单精通难 [Propmpt]是AGI时代的[编程语言][Propmpt]是AGI时代的[软件工程][提示工程]是…