【C++】异常的详细讲解

news2024/11/16 6:29:34

前言
C++是一门面向对象的语言,和面向过程的C语言有很多不一样的,其中这两种语言对程序错误的处理方式就不一样,通常面向对象是通过抛异常的方式来处理错误,而C语言则是通过返回错误码的方式。

目录

    • 1. C语言处理错误的方式
    • 2. C++异常的引入
      • 2.1 异常的概念:
      • 2.2 异常规范:
      • 2.3 自定义异常体系:
      • 2.3 异常的优缺点:

1. C语言处理错误的方式

传统处理错误的机制:

终止程序,如assert,缺陷:用户难以接受。如发生内存错误,除0错误时就会终止程序。
返回错误码
缺陷:

  • 需要程序员自己去查找对应的错误。如系统的很多库的接口函数都是通过把错误码放到errno中表示错误

实际中C语言基本都是使用返回错误码的方式处理错误,部分情况下使用终止程序处理非常严重的错误

  • 传统返回错误码的方式,每个调用的地方都需要检查返回值,都需要处理错误,比较麻烦。
% 我们打印了前十个错误码:
% 使用strerror()函数来打印错误码
int main()
{
	for (size_t i = 0; i < 10; i++)
	{
		cout << strerror(i) << endl;
	}

	return 0;
}

在这里插入图片描述

2. C++异常的引入

2.1 异常的概念:

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

C++新增了三个关键字:throw,try,catch。

  • throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
  • catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch关键字用于捕获异常,可以有多个catch进行捕获。
  • try: try 块中的代码标识将被激活的特定异常,它后面通常跟着一个或多个catch块。
try
{
// 保护的标识代码
}catch( ExceptionName e1 )
{
// catch 块
}catch( ExceptionName e2 )
{
// catch 块
}catch( ExceptionName eN )
{
// catch 块
}

注意:

  • 异常时通过抛出对象而引发的,该对象的类型决定了应该激活那个catch的处理代码
  • 异常是必须被捕获的,不然的话,会终止程序(很严重的错误)
  • 虽然可以抛出任意异常,但是Stl 库里面定义了一个异常类Exception,用来抛出异常。
  • catch(…)可以捕获任意类型的异常,问题是不知道异常错误是什么
  • 抛出异常对象后,会生成一个异常对象的拷贝,因为抛出的异常对象可能是一个临时对象,所以会生成一个拷贝对象,这个拷贝的临时对象会在被catch以后销毁。(这里的处理类似于函数的传值返回)
  • 实际中抛出和捕获的匹配原则有个例外,并不都是类型完全匹配,可以抛出的派生类对象,使用基类捕获,这个在实际中非常实用,我们后面会详细讲解这个

2.2 异常规范:

  • 函数的后面接throw(),表示函数不抛异常
  • 若无异常接口声明,则此函数可以抛掷任何类型的异常
// C++11 中新增的noexcept,表示不会抛异常
thread() noexcept;
thread (thread&& x) noexcept;
  • 构造函数完成对象的构造和初始化,最好不要在构造函数中抛出异常,否则可能导致对象不完整或没有完全初始化
  • 析构函数主要完成资源的清理,最好不要在析构函数内抛出异常,否则可能导致资源泄漏(内存泄漏、句柄未关闭等)
  • C++中异常经常会导致资源泄漏的问题,比如在new和delete中抛出了异常,导致内存泄漏,在lock和unlock之间抛出了异常导致死锁,
  • C++经常使用RAII来解决以上问题,关于RAII我们智能指针这节进行讲解。

2.3 自定义异常体系:

  • 实际使用中很多公司都会自定义自己的异常体系进行规范的异常管理
  • 因为一个项目中如果大家随意抛异常,那么外层的调用者基本就没办法玩了
  • 所以实际中都会定义一套继承的规范体系
  • 这样大家抛出的都是继承的派生类对象,捕获一个基类就可以了
    在这里插入图片描述
// 服务器开发中通常使用的异常继承体系
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;
}
  • 虽然C++库里面定义了Exception类,但是一般公司不喜欢用,觉得库里面的可拓展性比较差,会自己开发一个公司自己的类,方便大家使用,
    在这里插入图片描述

2.3 异常的优缺点:

C++异常的优点:
1.异常对象定义好了,相比错误码的方式可以清晰准确的展示出错误的各种信息。
2. 返回错误码的传统方式有个很大的问题就是,在函数调用链中,深层的函数返回了错误,那么我们得层层返回错误,最外层才能拿到错误.

C++异常的缺点:
1.常会导致程序的执行流乱跳,并且非常的混乱,并且是运行时出错抛异常就会乱跳。这会导致我们跟踪调试时以及分析程序时,比较困难。
2. 异常会有一些性能的开销。当然在现代硬件速度很快的情况下,这个影响基本忽略不计。
3. C++没有垃圾回收机制,资源需要自己管理。有了异常非常容易导致内存泄漏、死锁等异安全问题。这个需要使用RAII来处理资源的管理问题。学习成本较高。
4. C++标准库的异常体系定义得不好,导致大家各自定义各自的异常体系,非常的混乱。

总结:异常总体而言,利大于弊,所以工程中我们还是鼓励使用异常的。

尾声
看到这里,相信大家对这个C++有了解了。
如果你感觉这篇博客对你有帮助,不要忘了一键三连哦

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

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

相关文章

网络变压器原理与维修视频

如果你在寻找网络变压器原理与维修方面的视频教程&#xff0c;可以在网上找一些优质的资料进行学习。一些国内外知名的教育和科技资源网站&#xff0c;如B站、优酷、YouTube等&#xff0c;都有涉及网络变压器原理和维修的视频教程&#xff0c;你可以在这些网站上进行搜索。 通常…

ant design pro 6.0搭建教程

一、搭建 环境&#xff1a; Node.js 18.16.1 ant design pro 6.0 注意&#xff1a;选择umi3时&#xff0c;使用node.js 18版本的会报错&#xff0c;可以实践一下&#xff0c;这里就不再进行实践了。 umi3需要版本是低于node.js 18的 node下载地址&#xff1a; https://nodejs.…

【bugfix】/usr/local/bin/docker-compose:行1: html: 没有那个文件或目录

前言 在使用 docker-compose 管理容器化应用时&#xff0c;偶尔会遇到一些意想不到的错误&#xff0c;比如当尝试运行 docker-compose 命令时&#xff0c;终端非但没有展示预期的输出&#xff0c;反而出现类似网页错误的信息。这类问题通常与 docker-compose 的安装或配置有关…

虚拟化技术[2]之存储虚拟化

存储虚拟化 存储虚拟化简介存储虚拟化一般模型存储虚拟化实现方式基于主机存储虚拟化基于存储设备存储虚拟化基于网络存储虚拟化 案例分析&#xff1a;VMFSVMFS功能 存储虚拟化简介 存储虚拟化&#xff1a;将存储网络中的各个分散且异构的存储设备按照一定的策略映射成一个统一…

BL121DT网关在智能电网分布式能源管理中的应用钡铼技术协议网关

随着全球能源结构的转型和智能电网技术的飞速发展&#xff0c;分布式能源管理系统在提高能源利用效率、促进可再生能源接入及保障电网稳定运行方面发挥着日益重要的作用。然而&#xff0c;分布式能源系统内设备种类繁多&#xff0c;通信协议各异&#xff0c;如何高效整合这些设…

Modbus TCP转Profinet网关测试配置案例

本案例采用XD-ETHPN20网关做为Modbus TCP通信协议设备与Profinet通信协议设备连接的桥梁。Modbus TCP是一种基于TCP/IP协议的工业通信协议&#xff0c;而Profinet则是用于太网通信的协议。Modbus TCP转Profinet网关可实现这两种不同协议之间的数据交换和传输&#xff0c;极大地…

MySQL索引、视图练习

素材 1.学生表&#xff1a;Student (Sno, Sname, Ssex , Sage, Sdept) 学号&#xff0c;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;所在系 Sno为主键 2.课程表&#xff1a;Course (Cno, Cname,) 课程号&#xff0c;课程名 Cno为主键 3.学生选课表&#xff1a;SC (Sno…

FFMPEG 解码过程初步学习

1. 视频文件解码过程 解码过程 步骤如下&#xff1a; 视频文件&#xff08;封装格式&#xff0c;MP4/FLV/AVI 等&#xff09;获取视频格式信息等解复用为Stream 流&#xff0c; 准备解码用的Codec将Stream 流 使用解码器解为Raw 格式针 1.1 音视频格式填充&#xff1a; int…

升级版网创教程wordpress插件自动采集并发布

主要功能&#xff1a; wordpress 插件主题系列支持自动采集并发布。 主要采集: 福缘&#xff0c;中创&#xff0c;冒泡 自动采集各大项目网进行整合发布到自己个人网站 插件话更新&#xff0c;减少网络请求&#xff0c;提升稳定性 代码完美开源 傻瓜式操作&#xff0c;一…

第 398 场 LeetCode 周赛题解

A 特殊数组 I 模拟&#xff1a;遍历数组判断是否是一个特殊数组 class Solution { public:bool isArraySpecial(vector<int>& nums) {int r 0;while (r 1 < nums.size() && nums[r 1] % 2 ! nums[r] % 2)r;return r nums.size() - 1;} };B 特殊数组 I…

Aiseesoft iPhone Unlocker for Mac激活版:一键解锁工具

在数字时代&#xff0c;手机解锁问题时常困扰着我们。Aiseesoft iPhone Unlocker for Mac作为一款专为Mac用户打造的解锁工具&#xff0c;以其简洁易用的界面和强大的功能&#xff0c;成为了解决iPhone解锁问题的最佳选择。 Aiseesoft iPhone Unlocker for Mac激活版下载 Aisee…

Mysql之InnoDB索引

1.索引简介 官网介绍:MySQL :: MySQL 8.0 Reference Manual :: 10.3.1 How MySQL Uses Indexes 索引用于快速查找具有特定列值的行。如果没有索引&#xff0c; MySQL 必须从第一行开始&#xff0c;然后读取整个表以找到相关的行。表越大&#xff0c;花费就越多。如果表中有相关…

java项目之视频网站系统源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的视频网站系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 视频网站系统的主要使用者管…

Java进阶学习笔记15——接口概述

认识接口&#xff1a; Java提供了一个关键字Interface&#xff0c;用这个关键字我们可以定义一个特殊的结构&#xff1a;接口。 接口不能创建对象。 注意&#xff1a;接口不能创建对象&#xff0c;接口是用来被类实现&#xff08;implements&#xff09;的&#xff0c;实现接口…

意外发现openGauss兼容Oracle的几个条件表达式

意外发现openGauss兼容Oracle的几个条件表达式 最近工作中发现openGauss在兼容oracle模式下&#xff0c;可以兼容常用的两个表达式&#xff0c;因此就随手测试了一下。 查看数据库版本 [ommopenGauss ~]$ gsql -r gsql ((openGauss 6.0.0-RC1 build ed7f8e37) compiled at 2…

idea使用鼠标滚轮进行字体大小缩放

idea使用鼠标滚轮进行字体大小缩放 使用快捷键CtrlAltS进入到设置页面 在左上角搜索框输入“increase”&#xff0c;在左侧的Keymap中右击“Increase Fort Size”&#xff0c;点击“add mouse shortcut”&#xff0c;然后录入我们要设置的快捷键&#xff0c;比如我是点击ctrl鼠…

Unity Assembly Definition Dotween 引用

原理&#xff1a; 具体Unity程序集原理用法&#xff0c;暂时留坑&#xff0c;不介绍了&#xff0c;相信有很多人也写过了 这里简单放个官方API链接 https://docs.unity3d.com/cn/current/Manual/ScriptCompilationAssemblyDefinitionFiles.html 现象 &#xff1a;Dotween引用…

CATIA入门操作——为什么大佬的工具栏是水平的?如何把工具栏变水平?

目录 引出工具栏怎么变成水平&#xff1f;总结发生肾么事了&#xff1f;&#xff1f;鼠标中键旋转不了解决&#xff1a;特征树不显示参数关系 我的窗口去哪了&#xff1f;插曲&#xff1a;草图工具的调出插曲&#xff1a;颜色工具栏显示 弹窗警告警告&#xff1a;创建约束是临时…

bootstrap实现九宫格效果(猫捉老鼠游戏)

最近&#xff0c;孩子的幼儿园让家长体验“半日助教活动”&#xff0c;每个家长需要讲授15-20分钟的课程。作为一名程序员&#xff0c;实在没有能教的课程&#xff0c;只能做了一个小游戏&#xff0c;带着小朋友们熟悉数字。 效果大致是这样的。九宫格的左上角是一只小猫图片&…

VirtualBox+Ubuntu22.10+Docker+ROS2

Docker 拉取ros2镜像 docker pull osrf/ros:foxy-desktop 运行 docker run -it --nameros2 -p 50022:22 osrf/ros:foxy-desktop 进入容器安装组件 apt-get update apt-get install vim apt-get install git apt-get install net-tools # 安装ssh apt-get install openssh…