异常(C++)

异常

  • 前言
  • 一、程序的错误分类
  • 二、异常
    • 1. 概念
    • 2. 捕获异常的关键字和格式
    • 3. 异常的使用
      • 异常的原则
      • 异常再抛出
      • 异常说明
      • 注意事项
    • 4. 自定义异常体系
    • 5. C++标准库的异常体系
  • 三、总结

前言

  1. 在程序运行时经常碰到一些错误,例如年龄、身高不能为负,除数为0等,这些错误放到程序中如果不加以管制,程序就会崩溃。C++提供了异常机制,让我们能跟捕获运行时错误,给程序一次机会,给用户一个反馈。
  1. C++异常处理机制可以让我们捕获并进行处理错误,然后我们可以通过捕获后的判断,重新给程序指一条明路,或者在程序结束之前,做一些必要的工作,例如将错误写到日志等。

说到C++,C语言的处理错误方式也简单提一下:
assert宏

  1. 生产环境可能被禁用(会带来性能开销,并且不能对用户提供任何实际好处)编译器会优化掉。
  2. 开发环境可以用来检查条件,但是不提供详细的错误信息,并且终止程序。
  3. 只能用来检查布尔表达式,无法用于更复杂的逻辑和错误处理。

返回错误码

  1. 程序员要自己查找对应的错误,系统很多库函数也都是通过错误码(errno)表示错误

一、程序的错误分类

程序的错误大致可以分为三种,分别时语法错误、逻辑错误和运行时错误。

  1. 语法错误:在编译和链接阶段就能发现,必须全符合语法规则才能生成可执行代码。这种错误最简单。
  2. 逻辑错误:编码思路问题,执行的结果不是预定的,也可以通过调试解决。
  3. 运行时错误:程序运行期间发生的错误,如同除0,越界等。C++异常(Exception)机制就是为了解决这种错误。

二、异常

1. 概念

异常:异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛异常,让函数的直接或间接调用者处理这个错误。

2. 捕获异常的关键字和格式

C++异常处理涉及三个关键字

  • throw:出现问题,程序使用throw抛出异常
  • catch:有抛出也得有捕获,catch关键字就是用来捕获异常。捕获的地方就是处理问题的地方。
  • try:try块中的代码为保护代码,如果出错会激活特定的异常,后面跟着一个或多个catch块。

eg:语法

try{//保护区,就是可能会出错的代码
}
catch(ExceptionName e1){//出错后,通过异常处理程序捕获异常,在这里处理问题或者 再抛出
}
catch(ExceptionName e2){//因为异常对象类型的多样,所以可以多个catch块捕获匹配的异常
}
catch(...){//如果try块中出现异常,而前面的catch块也没有捕获,这是最后一道防线,所有类型都会在这里捕获,但不知道异常的错误原因。
}

注意: 可能有些不好理解,后面内容我会逐步介绍

3. 异常的使用

异常的原则

简单的例子:

double Division(int a, int b)
{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;
}int main()
{try {Func();}catch (const char* errmsg){cout << errmsg << endl;}catch (...){cout << "unknow exception" << endl;}return 0;
}

异常 栈调用
调用链

上例的函数调用链中栈的细节:

  1. 检查被throw是否在try块中,如果在并触发异常。
  2. 被throw抛出对象的类型和最近的catch块的参数进行匹配,匹配成功,则调到catch块中处理。没有匹配成功,则退出当前函数栈,在调用该函数的栈中继续匹配。
  3. 如果到main函数的栈依旧没有匹配,则终止程序(非正常结束)。但一般有catch(…)兜底。
  4. 如果匹配到catch子句处理完块中内容后,会沿着try,catch语句后继续执行

匹配原则

  1. throw抛出的对象类型与调用链中位置最近并且参数类型一样的catch匹配。
  2. throw抛出异常会生成一个异常对象的拷贝(因为抛出的对象可能是一个临时对象),这个拷贝的对象会被catch以后销毁。(类似函数传值返回)
  3. catch(…)可以捕获任意类型异常,但是不知道异常错误是什么。
  4. 匹配原则的例外:可以抛出派生类对象,使用基类捕获。(后面讲)

异常再抛出

一个单独的catch语句不能完整的处理某个异常,再执行一些校正操作之后,可能会抛给调用链更上一层的函数接着处理异常。
这个简单的校正工作可能就是改变参数内容,但是这里又要注意是不是引用
eg:

//简单的校正操作
catch (my_error& eObj){                     //引用类型 eObj.status = errCodes::severeErr;      //修改了异常对象throw;
}
catch (other_error eObj) {                     //非引用类型 eObj.status = errCodes::severeErr;         //只修改了异常对象的局部副本throw;
}

异常再抛出:

try
{//保护代码//...
}
catch (const char* errmsg)
{cout << errmsg << endl;
}
catch (...)
{throw;//异常再抛出,不含任何表达式//注意异常进行抛出后,是直接跳过这个函数栈的后面部分,例如下面的打印语句就  不会在进行执行cout << "unknow Exception" << endl;
}

异常说明

目的是为了让使用者知道该函数抛出的异常类型。

异常说明:

//这里表示这个函数会抛出A/B/C/D中的某种类型的异常
void func()  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 ();//若无异常接口声明:表示这个函数可以抛出任何类型的异常
void func1()

C++11新增的noexcept,表示不会抛出异常

void recoup(int) noexcept; //不会抛出异常
void alloc(int)            //可能抛出异常

注意: noexcept的位置也很特殊,因为const,final,override或者虚函数=0,都可以跟在函数后面,所以noexcept要在const及引用限定符之后,在final,override或者虚函数=0之前。

注意事项

建议

  1. 不要在构造函数中抛出异常(可能导致对象未完成初始化)
  2. 不要在析构函数中抛出异常(可能导致资源泄漏)
  3. 不要在lock和unlock之间抛异常(死锁)(后面的博客讲)

4. 自定义异常体系

实际很多公司会自己定义异常体系,规范管理。大家抛出的都是继承的派生类对象,捕获一个基类即可。

继承体系

eg:服务器开发中使用的异常继承体系(例子)

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:SqlException(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 (true){Sleep(500);      //引用系统头文件<Windows.h>try {HttpServer();}catch (const Exception& e) // 这里捕获父类对象就可以{// 多态cout << e.what() << endl;}catch (...){cout << "Unkown Exception" << endl;}}return 0;
}

5. C++标准库的异常体系

C++标准库的异常体系
注意: C++标准库的异常体系设计的不好用,所以一般都是定义自己的异常体系

三、总结

异常总体而言利大于弊

异常的优缺点

优点:

  1. 异常对象定义好了,可以更加清晰准确的展示出错误的各种信息,更好的定位bug。
  2. 不需要层层返回检查并错误码,异常体系直接跳到catch捕获的位置
  3. 很多第三方库都包含异常,想要使用这些库也需要使用异常
  4. 部分函数使用异常更好处理,例如没有返回值的或者不便于返回的。

缺点:

  1. 执行流乱跳,导致跟踪调试时以及分析程序困难,很混乱
  2. 性能的开销
  3. C++标准库的异常体系定义的不好,大家各自定义异常体系,不统一

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

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

相关文章

sql注入 [GXYCTF2019]BabySQli1

打开题目 多次尝试以后我们发现存在一个admin的账号&#xff0c;但是密码我们不知道 我们尝试一下万能密码 admin or 11 -- q 报错 我们尝试bp抓一下包看看 看着很像编码 先去base32解码 再base64解码 得到 我们从这个sql语句中得到注入点为name 根据报错信息我们知道是…

网络安全(一)--网络环境构成,系统的安全

2. 网络攻防环境 目标 了解攻防环境构成了解入侵检测系统&#xff08;平台&#xff09;的部署位置 2.1. 环境构成 2.1.1. 环境框图 一个基本的网络攻防实验环境包括&#xff1a;靶机、攻击机、入侵检测分析系统、网络连接四部分组成。 一个基础的网络攻防实验环境需要如下…

提取不重复的整数

输入一个 int 型整数&#xff0c;按照从右向左的阅读顺序&#xff0c;返回一个不含重复数字的新的整数。 保证输入的整数最后一位不是 0 。 输入&#xff1a;9876673 输出&#xff1a;37689 解题思路&#xff1a; 1、将输入的整数分别与10 相除&#xff0c;后得到的余数&…

阿里云租赁费用_阿里云服务器多配置报价表

阿里云服务器租用费用&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、轻量应用服务器2核2G3M带宽轻量服务器一年87元&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;ECS云服务器e系列2核2G配置99元一年、2核4G配置365元一年、2核8G配置522元一年…

Git多人协作(一)

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 前言 由于博主是一个人&#xff0c;所以博主为完成这篇文章&#xff0c;在Linux下克隆了一个仓库&#xff0c;在windows下克隆了一个仓库&#xff0c;以此来模拟多人协作开发。而实际开发中&#xff0c;每个人都有自己的git…

【CSP】202305-1_重复局面Python实现

文章目录 [toc]试题编号试题名称时间限制内存限制题目背景问题描述输入格式输出格式样例输入样例输出样例说明子任务提示Python实现 试题编号 202305-1 试题名称 重复局面 时间限制 1.0s 内存限制 512.0MB 题目背景 国际象棋在对局时&#xff0c;同一局面连续或间断出现3次或3…

python3安装lifelines

目录 一、环境 二、安装lifelines 出现问题 三、测试导入 一、环境&#xff1a; jupyter notebook中新建ipynb文件 二、安装lifelines pip install --upgrade --no-deps githttps://github.com/CamDavidsonPilon/lifelines.git出现问题&#xff1a; 缺少模块autograd、f…

sqlite3.44.2的编译

文章目录 sqlite3.44.2的编译概述笔记解决shell.c编译报错的方法整理 - 正常可用的编译脚本过程剩下的事情验证编译出的输出是否可以给工程正常使用?END sqlite3.44.2的编译 概述 想从源码编译一份Sqlite3.44.2出来. 编译sqlite3.44.2前置需要的TCL环境已经编译出来到了, 做…

软件手册目录

引言 1.1 介绍软件手册的目的 1.2 解释软件的背景和关键功能 安装与配置 2.1 硬件和软件要求 2.2 下载和安装 2.3 配置和设置 入门指南 3.1 界面导览 3.2 基本操作 3.3 软件功能概述 功能详解 4.1 功能1 4.1.1 功能描述 4.1.2 操作步骤 4.1.3 高级选项 4.2 功能2 … 常见问…

归并排序的非递归实现

归并排序的核心思想是分治&#xff0c;也就是将原数组切分成两个子数组分配排序再将排好序的两个子数组进行合并&#xff0c;之前的文章已经讲过递归版本的实现&#xff0c;现在我们看看非递归版本的实现 第一种思路&#xff1a;用步长来切分数组&#xff0c;也就是我们在切分…

docker安装informix

docker安装informix 通过docker下载镜像 docker pull ibmcom/informix-developer-database 启动容器 docker run -it -d --name informix --privileged -p 9088:9088 -p 9089:9089 -p 27017:27017 -p 27018:27018 -p 27883:27883 -e LICENSEaccept ibmcom/informix-develope…

RestTemplate发送请求、基本spring自带RestTemplate发送请求、RestTemplate设置请求头

今天分享RestTemplate&#xff0c;直接上代码&#xff1a; 因个人需求需要重写RestTemplate&#xff0c;并设置请求头 import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvide…

学习Python能给我们带来什么?有什么帮助?

文章目录 前言学习Python能做什么1、抓取各类数据、文本等信息2、批量清洗和处理数据3、提供可视化工具4、进行深度学习 Python的用途有哪些普通人学习python有什么好处关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python…

要求CHATGPT高质量回答的艺术:提示工程技术的完整指南—第 4 章:控制温度和 Top-p 采样

要求CHATGPT高质量回答的艺术&#xff1a;提示工程技术的完整指南—第 4 章&#xff1a;控制温度和 Top-p 采样 控制温度和 Top-p 采样是用于管理人工智能语言模型在生成文本时输出的创造性、连贯性和集中性的技术。 让我们打一个比方来简化它&#xff1a;把人工智能想象成一…

Linux挂载配置本地yum源

1.vi /etc/yum.repos.d/redhat.repo 2. [baseos] namebaseos baseurlfile:///mnt/BaseOS #enabled:默认为1 enabled1 gpgcheck0 [appstream] nameappstream baseurlfile:///mnt/AppStream enabled1 gpgcheck0 3. mount /dev/sr0 /mnt/ 4.yum clean all 5.yum makecache

神秘鸭是如何让你的手机控制你的电脑的?

神秘鸭 神秘鸭即是一个应用&#xff0c;它能让手机语音助手、智能音箱变的更为强大&#xff01;通过神秘鸭&#xff0c;您的手机语音助手、智能音箱可以用来控制电脑、智能家居、DIY的物联网设备。 支持的手机、平板品牌 Apple 华为 小米 三星 OPPO VIVO 一加 当然不代表仅支…

感兴趣书单汇总

文章目录 声明科幻小说哲学书数学 声明 本帖持续更新 科幻小说 《三体》&#xff08;已读&#xff09;《献给阿尔吉侬的花束》&#xff08;已读&#xff09; 哲学书 数学 《Principia Mathematica》&#xff08;未读&#xff09;&#xff1a;怀特海德和罗素所著&#xff…

C# Solidworks二次开发:创建坐标系方法和获取零件质心坐标方法详解

今天要讲的是如何在Solidworks创建坐标系和获取零件的质心方法详解&#xff0c;创建坐标系的API如下所示&#xff1a; 1、创建坐标系API如下所示&#xff1a;Feature swCoordSys1 swFeatMgr.InsertCoordinateSystem(false, false, false); 其中方法的输入参数有三个&#xf…

1466. 重新规划路线 --力扣 --JAVA

题目 n 座城市&#xff0c;从 0 到 n-1 编号&#xff0c;其间共有 n-1 条路线。因此&#xff0c;要想在两座不同城市之间旅行只有唯一一条路线可供选择&#xff08;路线网形成一颗树&#xff09;。去年&#xff0c;交通运输部决定重新规划路线&#xff0c;以改变交通拥堵的状况…

SpringBoot 知识梳理

学习目标 掌握基于 SpringBoot 框架的程序开发步骤熟练使用基于 SpringBoot 配置信息修改服务器配置基于 SpringBoot 的完成 SSM 整合项目开发 1 SpringBoot 简介 1.1 入门案例 1.1.1 步骤 ① &#xff1a;创建新模块&#xff0c;选择 Spring 初始化&#xff0c;并配置模块…