C++异常学习

C语言传统的处理错误的方式

传统的错误处理机制:

  1. 终止程序,如assert,缺陷:用户难以接受。如发生内存错误,除0错误时就会终止程序。
  2. 返回错误码,缺陷:需要程序员自己去查找对应的错误。如系统的很多库的接口函数都是通
    过把错误码放到errno中,表示错误
    实际中C语言基本都是使用返回错误码的方式处理错误,部分情况下使用终止程序处理非常严重的
    错误。

C++异常概念

异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的
直接或间接的调用者处理这个错误。
throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
catch: 在您想要处理问题的地方,通过异常处理程序捕获异常.catch 关键字用于捕获异
常,可以有多个catch进行捕获。
try: try 块中的代码标识将被激活的特定异常,它后面通常跟着一个或多个 catch 块。
如果有一个块抛出一个异常,捕获异常的方法会使用 try 和 catch 关键字。try 块中放置可能抛
出异常的代码,try 块中的代码被称为保护代码。使用 try/catch 语句的语法如下所示:

try
{// 保护的标识代码
}catch( ExceptionName e1 )
{// catch 块
}catch( ExceptionName e2 )
{// catch 块
}catch( ExceptionName eN )
{// catch 块
}

异常的使用

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

  1. 异常是通过抛出对象而引发的,该对象的类型决定了应该激活哪个catch的处理代码。
  2. 被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个。
  3. 抛出异常对象后,会生成一个异常对象的拷贝,因为抛出的异常对象可能是一个临时对象,
    所以会生成一个拷贝对象,这个拷贝的临时对象会在被catch以后销毁。(这里的处理类似
    于函数的传值返回)
  4. catch(…)可以捕获任意类型的异常,问题是不知道异常错误是什么。
  5. 实际中抛出和捕获的匹配原则有个例外,并不都是类型完全匹配,可以抛出的派生类对象,
    使用基类捕获,这个在实际中非常实用,我们后面会详细讲解这个。

在函数调用链中异常栈展开匹配原则
6. 首先检查throw本身是否在try块内部,如果是再查找匹配的catch语句。如果有匹配的,则
调到catch的地方进行处理。
7. 没有匹配的catch则退出当前函数栈,继续在调用函数的栈中进行查找匹配的catch。
8. 如果到达main函数的栈,依旧没有匹配的,则终止程序。上述这个沿着调用链查找匹配的
catch子句的过程称为栈展开。所以实际中我们最后都要加一个catch(…)捕获任意类型的异
常,否则当有异常没捕获,程序就会直接终止。
9. 找到匹配的catch子句并处理以后,会继续沿着catch子句后面继续执行。
在这里插入图片描述
看代码

#include<iostream>
using namespace std;
int divs(int m, int n)
{if (n == 0){throw"被除数不能为0";}return m / n;
}void func1(int m ,int n )
{divs(m, n);
}void func2(int m, int n)
{func1(m, n);
}void func3(int m, int n)
{func2(m, n);
}int main()
{try{int m, n;cin >> m >> n;func3(m, n);}catch (const char* s){cout << s << endl;}catch (...){cout << 11 << endl;}return 0;
}

在这里插入图片描述
很高兴,这里学到了一个新的知识点,之前学的太马虎了

#include<iostream>
#include<string>
using namespace std;
int divs(int m, int n)
{if (n == 0){throw"被除数不能为0";}return m / n;
}void func1(int m ,int n )
{divs(m, n);
}void func2(int m, int n)
{func1(m, n);
}void func3(int m, int n)
{func2(m, n);
}int main()
{try{int m, n;cin >> m >> n;func3(m, n);}catch (string s){cout << s << endl;}catch (...){cout << 11 << endl;}return 0;
}

用下面的代捕获就不行,就不知道原因,我throw不就是一个字符串吗,为什么不能接受。后来发现,throw抛出的是字符串常量,跟string类型确实不一样。我们创建一个string是怎么样的啊?
string s =“ssss”;
其实这里就是把字符串常量变成string类型。
下面是chat老师的解释

你的代码中使用 throw “被除数不能为0”; 时,抛出的异常是一个字符串常量,其类型是 const char* 而不是 std::string。因此,在 catch 块中,你应该捕获 const char* 类型的异常而不是 std::string。

如果你想要用 std::string 来捕获这个异常,你应该在抛出异常时使用 std::string 类型,像这样:throw std::string(“被除数不能为0”);。

字符串常量跟string有什么区别呢
ChatGPT
字符串常量和 std::string 类型在 C++ 中有几个主要的区别,这些区别涉及它们的类型定义、内存管理、使用方式和功能。这里是一些关键区别:

  1. 类型和存储
    字符串常量(如 “hello”)是由编译器在编译时处理的,它们实际上是 const char[] 类型,即一个以 null (‘\0’) 字符结束的字符数组。这些字符串存储在程序的只读数据段中,通常不能被修改。
    std::string 是 C++ 标准库中定义的一个类,用于处理文本数据。它封装了动态数组的管理,可以容纳可变长度的字符串,并提供了广泛的成员函数来进行字符串操作。std::string 对象通常存储在堆上,或者在小字符串优化 (SSO) 情况下在栈上。
  2. 内存管理
    字符串常量 不需要用户进行内存管理,它们由编译器管理,并且通常不能被修改。
    std::string 管理它自己的内存,自动进行内存分配和释放。它支持动态改变大小,可以在运行时添加、修改或删除字符。
  3. 功能和方法
    字符串常量 基本上只能用作不变的文本。要执行任何复杂的操作(如拼接、搜索或替换),你需要使用 C 风格的字符串处理函数(如 strlen, strcpy, strcat 等)。
    std::string 提供了许多成员函数和运算符重载,使得字符串处理更加直接和安全。例如,你可以使用 + 运算符来拼接字符串,使用 [] 运算符来访问特定位置的字符,以及使用 .length() 或 .size() 来获取字符串的长度等。
  4. 安全性和方便性
    使用 字符串常量 可能会涉及到指针操作,这在不正确使用的情况下可能导致程序崩溃或安全问题(例如缓冲区溢出)。
    std::string 设计时考虑到安全性和方便性,自动处理内存管理,减少了缓冲区溢出的风险,并简化了代码。

查看异常捕获机制

#define  _CRT_SECURE_NO_WARNINGS#include<iostream>
using namespace std;
int divs(int m, int n)
{if (n == 0){throw"被除数不能为0";}return m / n;
}void func1(int m, int n)
{divs(m, n);
}void func2(int m, int n)
{try{func1(m, n);}catch (const char* s){cout << __LINE__ << endl;}cout << 1111 << endl;}void func3(int m, int n)
{func2(m, n);
}int main()
{try{int m, n;cin >> m >> n;func3(m, n);}catch (const char* s){cout << __LINE__ << endl;cout << s << endl;}catch (...){cout << 11 << endl;}return 0;
}

在这里插入图片描述
自定义异常类
在这里插入图片描述

#define  _CRT_SECURE_NO_WARNINGS
#include<string>
#include <time.h>
using namespace std;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 HttpServer()
{// ...srand(time(0));if (rand() % 3 == 0){throw HttpServerException("请求资源不存在", 100, "get");}else if (rand() % 4 == 0){throw HttpServerException("权限不足", 101, "post");}CacheMgr();
}
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();
}int main()
{while (1){this_thread::sleep_for(chrono::seconds(1));try {HttpServer();}catch (const Exception& e) // 这里捕获父类对象就可以{// 多态std::cout << e.what() << std::endl;}catch (...){std::cout << "Unkown Exception" << std::endl;}}return 0;
}

异常规范

  1. 异常规格说明的目的是为了让函数使用者知道该函数可能抛出的异常有哪些。 可以在函数的
    后面接throw(类型),列出这个函数可能抛掷的所有异常类型。
  2. 函数的后面接throw(),表示函数不抛异常。
  3. 若无异常接口声明,则此函数可以抛掷任何类型的异常。
// 这里表示这个函数会抛出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;

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

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

相关文章

ES增强框架easy-es

因为最近做的功能是关于舆情的,所以数据量比较大的,本来打算用MySQL做时间分表来做,但是经过一段时间的测试,发现数据量太大,用时间分表不能满足性能的要求,所以决定将数据存储改为ES,但是短时间内改底层框架又不是一个小工程,时间上不允许,所以找到了一个很合适的框架,他跟myb…

深入理解JVM中的G1垃圾收集器原理、过程和参数配置

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;垃圾收集&#xff08;GC&#xff09;是一个自动管理内存的过程&#xff…

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第四套

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第四套 (共9套&#xff0c;有答案和解析&#xff0c;答案非官方&#xff0c;仅供参考&#xff09;&#xff08;共九套&#xff0c;每套四十个选择题&#xff09; 部分题目分享&#xff0c;完整版获取&#xff08;WX:didadida…

「GO基础」起源与演进

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

一文讲明白什么是市场调研

本文主要介绍市场调研的主要步骤和工具方法&#xff0c;并简单介绍了淘宝在电商领域中市场调研的实践。 什么是调研 ▐ 定义 广义的含义&#xff0c;调研既是指市场调查&#xff0c;通过收集、分析和解释相关数据来达到了解企业现状、了解市场趋势、挖掘用户需求、确定产品研发…

『哈哥赠书 - 51期』-『数字风控体系:设计与实践』

⭐️ 赠书 - 《数字风控体系&#xff1a;设计与实践》 ⭐️ 数字风控概述 从2007年开始到2014年左右&#xff0c;高速移动网络和智能手机迅速在大众中普及&#xff0c;开启了移动互联网时代。在这个背景下&#xff0c;企业的产品与服务也出现了两个重要的趋势。 第一个趋势是…

VUE3 + Elementui-Plus 之 树形组件el-tree 一键展开(收起);一键全选(不全选)

需求&#xff1a; 产品要求权限树形结构添加外部复选框进行全部展开或收起&#xff1b;全选或不全选。 实现步骤&#xff1a; tree组件部分&#xff1a; <div class"role-handle"><div>权限选择(可多选)</div><div><el-checkbox v-mode…

Git回滚版本并push到远端master

1、查看日志 git log 2、还原最近的版本 () --git reset --hard commit-id 如&#xff1a;git reset --hard d84da14bf2743683eca7a015f56114faaa344f42 3、覆盖分支版本 git push -f origin dev 回滚本地master完成后&#xff0c;将回滚后的代码push到远端master&#xf…

C++笔记:异常

文章目录 C 运行时错误处理机制及其不足之处C 异常概念异常的使用异常的抛出和匹配原则在函数调用链中异常栈展开匹配原则异常的重新抛出举例演示说明例子一&#xff1a;串联举例演示大部分原则例子二&#xff1a;模拟服务器开发中常用的异常继承体系例子三&#xff1a;异常的重…

C++初级----list(STL)

1、 list介绍 1.1、 list介绍 1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 1. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向 其前一…

集成定制化软件的销售推广渠道有哪些?

集成定制化软件的销售推广渠道可以包括以下几个方面&#xff1a; 一、线上渠道&#xff1a; 官方网站&#xff1a;建立专业的官方网站&#xff0c;展示软件的功能、优势、案例等&#xff0c;提供试用或购买链接。社交媒体&#xff1a;利用微博、微信、抖音等社交媒体平台&#…

SpringBoot中的动态编程实战原来是这么玩的

Java 开发已经有越来越多的 Groovy 出现在后台了。 而对于一般的应用开发&#xff0c;只要能用 Java 就都能用到 Groovy&#xff0c;唯一的难点只在于能不能招到足够的人员。 注&#xff1a;今天我们分享的就是利用Groovy脚本在SpringBoot项目中实现动态编程&#xff0c;使业务…

【YOLOv8改进[Neck]】使用BiFPN助力V8更优秀

目录 一 BiFPN(双向特征金字塔网络) 1 BiFPN 2 EfficientDet 二 使用BiFPN助力模型更优秀 1 整体修改 2 配置文件 3 训练 其他 一 BiFPN(双向特征金字塔网络) BiFPN(双向特征金字塔网络&#xff0c; 2020)用于特征融合层。 官方论文地址&#xff1a;https://arxiv.org…

鸢尾花数据集分类(决策树,朴素贝叶斯,人工神经网络)

目录 一、决策树 二、朴素贝叶斯 三、人工神经网络 四、利用三种方法进行鸢尾花数据集分类 一、决策树 决策树是一种常用的机器学习算法&#xff0c;用于分类和回归任务。它是一种树形结构&#xff0c;其中每个内部节点表示一个特征或属性&#xff0c;每个分支代表这个特征…

Spring容器结构

文章目录 1.基本介绍1.Spring5官网2.API文档3.Spring核心学习内容4.几个重要概念 2.快速入门1.需求分析2.入门案例1.新建Java项目2.导入jar包3.编写Monster.java4.src下编写Spring配置文件1.创建spring配置文件&#xff0c;名字随意&#xff0c;但是需要放在src下2.创建Spring …

SparkUI 讲解

目录 Executors Environment Storage SQL Exchange Sort Aggregate Jobs Stages Stage DAG Event Timeline Task Metrics Summary Metrics Tasks &#x1f490;&#x1f490;扫码关注公众号&#xff0c;回复 spark 关键字下载geekbang 原价 90 元 零基础入门 Spar…

IDEA2023 开发环境配置

目录 1. 关闭IDEA自动更新1.2 IDEA 新版样式切换 2. Maven配置2.1本地仓库优先加载2.2 maven.config配置文件中 3. 全局配置JDK4. 配置文件编码:UTF-85. 开启自动编译&#xff08;全局配置&#xff09;6. 开启自动导包7. 开启鼠标悬浮&#xff08;提示文档信息&#xff09;8. 设…

golang 使用栈模拟计算器

思路&#xff1a; // Author sunwenbo // 2024/4/12 16:51 package mainimport ("errors""fmt""strconv" )// 使用数组来模拟一个栈的应用 type Stack struct {MaxTop int //表示栈最大可以存放数的个数Top int //表示栈底&#xff…

2024年阿里云4核8G配置云服务器价格低性能高!

阿里云4核8G服务器租用优惠价格700元1年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采用Intel(R) Xeon(R) Platinum处理器&#xff0c;阿里云优惠 aliyunfuwuqi…

代码随想录算法训练营第二十九天|491.递增子序列、46.全排列、46.全排列II

491. 非递减子序列 思路&#xff1a; 在90.子集II (opens new window)中我们是通过排序&#xff0c;再加一个标记数组来达到去重的目的。 而本题求自增子序列&#xff0c;是不能对原数组进行排序的&#xff0c;排完序的数组都是自增子序列了。 所以不能使用之前的去重逻辑&…