C++异常处理

目录

一、C语言的异常处理方式

二、C++异常处理基本概念

三、异常处理的使用

1.异常抛出和捕获的匹配原则

2.异常的重新抛出

3.不建议抛出异常的情况

4.抛出异常规范

四、抛出派生类对象,使用基类捕获


一、C语言的异常处理方式

C语言对于异常处理方式通常为直接终止程序并返回错误码(大部分函数接口都会将错误码放在errno中以示错误原因)

直接终止程序用户难以接受,返回错误码又需要程序员自己查找对应的错误。

错误码及其对应的错误原因如下:

二、C++异常处理基本概念

C++中引入了异常,异常是一种错误处理方式。当一个函数出现自己无法处理的错误时,就可以抛出异常,让函数的调用者处理该异常。

  • throw:函数通过throw关键字抛出异常
  • try:标记可能会抛出异常的代码块,如果抛出异常后程序会立即跳转到与try标记块相关联的catch子句处
  • catch:捕获并处理异常,每个try块之后可能会有多个catch子句处理不同的异常,每一个catch子句中都声明了异常类型并定义了一个异常对象

三、异常处理的使用

1.异常抛出和捕获的匹配原则

C++的异常抛出其实是抛出一个异常对象,该异常对象的类型决定了与哪个catch异常处理子句匹配。抛出异常对象后,会调用异常对象的拷贝构造生成一个异常对象的拷贝,因为抛出的异常对象是函数生成的局部对象,只存在于当前函数栈帧中,而异常处理可能会涉及多个函数栈帧。

匹配原则:

函数抛出异常后,首先会检查throw是否在try块内部:

  • 如果在try块内部,选择最近的且类型匹配catch子句。如果没有类型匹配的catch子句,则退出当前函数栈帧,在调用函数的栈帧中查找匹配的catch子句,直到查找到匹配的catch子句。如果查找到main函数的栈帧依旧没有找到匹配的catch子句,则程序终止。
  • 如果不在try块内部,则退出当前函数栈帧,跳到调用函数的栈帧中看是否在try块内部,直到跳转到try块背部,重复第一点操作
double Div(double x, double y)
{if (y == 0)throw "Dividing by 0";//抛出异常elsereturn x / y;
}
void Func()
{int a, b;std::cin >> a >> b;std::cout << Div(a, b) << std::endl;
}
int main()
{try {Func();}catch (const char* error_msg){std::cout << error_msg << std::endl;}catch (int error_msg){std::cout << error_msg << std::endl;}catch (...){std::cout << "unknown exception" << std::endl;}return 0;
}
2.异常的重新抛出

有时候单个的catch子句并不能完全处理一个异常,catch子句在对异常进行一些校正处理后,可以将该异常重新抛出给更上层的调用函数来处理。

double Div(double x, double y)
{if (y == 0)throw "Dividing by 0";//抛出异常elsereturn x / y;
}
void Func()
{int* arr = new int[10];try {int a, b;std::cin >> a >> b;std::cout << Div(a, b) << std::endl;}catch (...){std::cout << "delete []" << arr << std::endl;delete[] arr;throw;//重新抛出异常}std::cout << "delete []" << arr << std::endl;delete[] arr;
}
int main()
{try {Func();}catch (const char* error_msg){std::cout << error_msg << std::endl;}catch (int error_msg){std::cout << error_msg << std::endl;}catch (...){std::cout << "unknown exception" << std::endl;}return 0;
}
3.不建议抛出异常的情况

随意抛出异常可能会导致程序错误,为了异常安全,下面几种情况建议不要抛出异常

  • 在构造函数中不要抛出异常,构造函数负责对象的构造和初始化,如果在构造函数中抛出异常可能会导致对象不完整或者没有完全初始化
  • 在析构函数中不要抛出异常,析构函数负责完成资源的清理,如果在析构函数中抛出异常可能会导致资源泄露问题
  • 在new和delete中不要抛出异常,可能会导致资源泄露
  • 在lock和unlock之间不要抛出异常,可能会导致死锁
4.抛出异常规范
  • 为了让函数使用者知道函数可能抛出哪些异常,在函数声明后接上throw(A,B,C,D),A,B,C,D表示抛出异常的类型
  • 有些函数不抛出异常,在函数声明后接上throw()
  • C++11中表示函数不需要抛出异常,在函数声明后接上noexcept
// 这里表示这个函数会抛出A/B/C/D中的某种类型的异常
void fun() throw(A,B,C,D);
// 这里表示这个函数只会抛出bad_alloc的异常
void* operator new (std::size_t size) throw (std::bad_alloc);
// 这里表示这个函数不会抛出异常
void* operator delete (std::size_t size, void* ptr) throw();
// C++11 中新增的noexcept,表示不会抛异常
thread() noexcept;
thread (thread&& x) noexcept;

四、抛出派生类对象,使用基类捕获

实际使用中很多公司都会自定义自己的异常体系进行规范的异常管理,因为一个项目中如果大家
随意抛异常,那么外层的调用者基本就没办法玩了,所以实际中都会定义一套继承的规范体系。
这样大家抛出的都是继承的派生类对象,捕获一个基类就可以了。

// 服务器开发中通常使用的异常继承体系
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 = '张三'");}//throw "xxxxxx";
}
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()
{while (1){this_thread::sleep_for(chrono::seconds(1));try {HttpServer();}catch (const Exception& e) // 这里捕获父类对象就可以{// 多态cout << e.what() << endl;}catch (...){cout << "Unkown Exception" << endl;}}return 0;
}

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

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

相关文章

VScode 开发 Springboot 程序

1. 通过maven创建springboot程序 输入 mvn archetype:generate 选择模板&#xff0c;一般默认选择为第 7 种方式&#xff1b; 选择之后&#xff0c;一般要你填写如下内容&#xff1a; groupId: 组织名称&#xff1b;artifactId: 项目名称&#xff1b;version: 版本&#xff0…

12Express简易实战项目(编写api)

12Express简易实战项目 1.初始化1.1 创建项目1.2 配置 cors 跨域1.3配置解析表单数据的中间件1.4 初始化路由相关的文件夹1.5 初始化用户路由模块1.6 抽离用户路由模块中的处理函数 2.登录注册2.1 新建 ev_users 表2.2 安装并配置 mysql 模块2.3 注册(1)实现步骤(2)检测表单数据…

Windows系统Tai时长统计工具的使用体验

Windows系统Tai时长统计工具的使用体验 一、Tai介绍1.1 Tai简介1.2 安装环境要求 二、下载及安装Tai2.1 下载Tai2.2 运行Tai工具 三、Tai的使用体验3.1 系统设置3.2 时长统计3.3 分类管理 四、总结 一、Tai介绍 1.1 Tai简介 Tai是一款专为Windows系统设计的开源软件&#xff…

数据结构——二叉树——堆(1)

今天&#xff0c;我们来写一篇关于数据结构的二叉树的知识。 在学习真正的二叉树之前&#xff0c;我们必不可少的先了解一下二叉树的相关概念。 一&#xff1a;树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层…

Vue入门(Vue基本语法、axios、组件、事件分发)

Vue入门 Vue概述 Vue (读音/vju/&#xff0c;类似于view)是一套用于构建用户界面的渐进式框架&#xff0c;发布于2014年2月。与其它大型框架不同的是&#xff0c;Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三…

数据结构:二叉树—面试题(二)

1、二叉树的最近公共祖先 习题链接https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/description/ 描述&#xff1a; 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点…

使用python-docx包进行多文件word文字、字符批量替换

1、首先下载pycharm。 2、改为中文。 3、安装python-docx包。 搜索包名字&#xff0c;安装。 4、新建py文件&#xff0c;写程序。 from docx import Documentdef replace1(array1):# 替换词典&#xff08;标签值按实际情况修改&#xff09;dic {替换词1: array1[0], 替换…

[操作系统] 进程地址空间管理

虚拟地址空间的初始化 缺页中断 缺页中断的概念 缺页中断&#xff08;Page Fault Interrupt&#xff09; 是指当程序访问的虚拟地址在页表中不存在有效映射&#xff08;即该页未加载到内存中&#xff09;时&#xff0c;CPU 会发出一个中断信号&#xff0c;请求操作系统加载所…

万字长文总结前端开发知识---JavaScriptVue3Axios

JavaScript学习目录 一、JavaScript1. 引入方式1.1 内部脚本 (Inline Script)1.2 外部脚本 (External Script) 2. 基础语法2.1 声明变量2.2 声明常量2.3 输出信息 3. 数据类型3.1 基本数据类型3.2 模板字符串 4. 函数4.1 具名函数 (Named Function)4.2 匿名函数 (Anonymous Fun…

【Linux】21.基础IO(3)

文章目录 3. 动态库和静态库3.1 静态库与动态库3.2 静态库的制作和使用原理3.3 动态库的制作和使用原理3.3.1 动态库是怎么被加载的 3.4 关于地址 3. 动态库和静态库 3.1 静态库与动态库 静态库&#xff08;.a&#xff09;&#xff1a;程序在编译链接的时候把库的代码链接到可…

Linux系统之gzip命令的基本使用

Linux系统之gzip命令的基本使用 一、gzip命令简介二、gzip命令使用帮助2.1 help帮助信息2.2 选项解释 三、gzip命令的基本使用3.1 压缩文件3.2 保留原始文件3.3 解压文件3.4 查看压缩信息3.5 标准输出/输入3.6 批量处理文件3.7 递归解压缩目录3.8测试压缩文件完整性 四、注意事…

【Matlab高端绘图SCI绘图模板】第05期 绘制高阶折线图

1.折线图简介 折线图是一个由点和线组成的统计图表&#xff0c;常用来表示数值随连续时间间隔或有序类别的变化。在折线图中&#xff0c;x 轴通常用作连续时间间隔或有序类别&#xff08;比如阶段1&#xff0c;阶段2&#xff0c;阶段3&#xff09;。y 轴用于量化的数据&#x…

免费SSL证书申请,springboot 部署证书

申请免费域名证书,SSL证书(一共有两个有用&#xff0c;一个是私钥private.key 另一个是certificate.crt) 1、打开网址 申请免费域名证书,SSL证书 2、选择生成CSR 3、生成以后点击下一步&#xff08;private key 有用 ) ​​​​​​​ 4、这里选择 Cname域名解析验证 5、…

Java 大视界 -- Java 大数据中的隐私增强技术全景解析(64)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

深度学习项目--基于LSTM的糖尿病预测探究(pytorch实现)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 LSTM模型一直是一个很经典的模型&#xff0c;一般用于序列数据预测&#xff0c;这个可以很好的挖掘数据上下文信息&#xff0c;本文将使用LSTM进行糖尿病…

js/ts数值计算精度丢失问题及解决方案

文章目录 概念及问题问题分析解决方案方案一方案二方案其它——用成熟的库 概念及问题 js中处理浮点数运算时会出现精度丢失。js中整数和浮点数都属于Number数据类型&#xff0c;所有的数字都是以64位浮点数形式存储&#xff0c;整数也是如此。所以打印x.00这样的浮点数的结果…

vite环境变量处理

环境变量: 会根据当前代码环境产生值的变化的变量就叫做环境变量 代码环境: 开发环境测试环境预发布环境灰度环境生产环境 举例: 百度地图 SDK,小程序的SDK APP_KEY: 测试环境和生产环境还有开发环境是不一样的key 开发环境: 110 生产环境:111 测试环境: 112 我们去请求第三…

Android GLSurfaceView 覆盖其它控件问题 (RK平台)

平台 涉及主控: RK3566 Android: 11/13 问题 在使用GLSurfaceView播放视频的过程中, 增加了一个播放控制面板, 覆盖在视频上方. 默认隐藏setVisibility(View.INVISIBLE);点击屏幕再显示出来. 然而, 在RK3566上这个简单的功能却无法正常工作. 通过缩小视频窗口可以看到, 实际…

Linux 环境变量

目录 一、环境变量的基本概念 1.常见环境变量 2.查看环境变量方法 ​3.几个环境变量 环境变量&#xff1a;PATH 环境变量&#xff1a;HOME 环境变量&#xff1a;SHELL 二、和环境变量相关的命令 三、库函数getenv&#xff0c;setenv 四、环境变量和本地变量 五、命令行…

Redis实战(黑马点评)——涉及session、redis存储验证码,双拦截器处理请求

项目整体介绍 数据库表介绍 基于session的短信验证码登录与注册 controller层 // 获取验证码PostMapping("code")public Result sendCode(RequestParam("phone") String phone, HttpSession session) {return userService.sendCode(phone, session);}// 获…