C++进阶 —— 异常

c++(11)异常处理 很不做的PPT 立即下载

目录

一,异常概念

二,异常的使用

三,自定义异常体系

四,C++标准库的异常体系

五,异常的优缺点


C语言传统处理错误机制

  • 终止程序,如assert;
  • 返回错误码,系统很多库接口函数通过把错误码放到errno中表示错误;
  • C标准库中setjmp/longjmp组合(不常用);

一,异常概念

        异常,是指程序在运行过程中遇到错误或其他异常情况(如除零、越界等),此时程序会立即跳转到处理该异常的代码处,以执行相应代码;异常是一种处理的方式,如当一函数发现自己无法处理的错误时就可抛出异常,让函数的直接或间接的调用者处理此错误;

        在C++中可使用try-catch语句来捕获和处理异常,try语句用于抛出异常,catch语句用于捕获并处理异常;

  • try,关键字,用于标记异常处理区域,可在程序发生异常时捕获并进行相应的处理;
  • throw,关键字,用于当出现问题时程序抛出异常,并将程序控制权转移到对应catch;
  • catch,关键字,捕获对应的异常,可有多个catch进行捕获;
try
{
    //抛出异常
	throw 表达式; //表达式值的类型可以是基本类型或自定义类型
}
catch (异常类型1) //异常类型通常是异常对象的指针或引用
{
	//异常1处理代码
}
catch (异常类型2)
{
	//异常2处理代码
}
...
catch (异常类型3)
{
	//异常3处理代码
}

二,异常的使用

异常的抛出和捕获

  • 异常是通过抛出对象而引发的,该对象的类型决定了应被哪个catch捕获;
  • 捕获后的处理代码,是调用链中与该对象类型相匹配,且离抛出异常位置最近的那一个;
  • 抛出异常对象后,会生成一个异常对象的拷贝;
    • 由于抛出的异常对象可能是一个临时对象,所以会生成一个拷贝对象;
    • 这个拷贝的临时对象会在被catch以后销毁;
  • catch(...)可以捕获任意类型的异常,但不知道抛出的错误是什么;
  • 实际中抛出或捕获异常的匹配原则并不都是类型完全匹配;
    • 可抛出为派生类对象,使用基类捕获,这个在实际中非常实用;

在函数调用链中异常栈展开匹配原则

栈展开,沿以下调用链查找匹配的catch:

  • 首先检查throw本身是否在try块内部,如在,查找匹配的catch语句;
    • 如有匹配的catch,则跳到catch的地方处理;
      • 找到匹配的catch子句并处理以后,会继续沿着catch子句后面继续执行;
    • 如没有匹配的catch,则退出当前函数栈,继续在调用函数的栈中进行查找匹配的catch;
    • 直到到达main函数的栈,依旧没有匹配的则终止程序;

        所以实际中最后都要加一个catch(...)捕获任意类型的异常,否则当前异常没捕获,程序会直接终止;

double Division(int a, int b) {
	if (b == 0)
		throw "Division by zero condition!";
	else
		return (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 << "unkown exception" << endl;
	}
	return 0;
}

异常的重新抛出

        有可能单个的catch不能完全处理一个异常,在进行一些校正处理后,希望在交给更外层的调用链函数来处理,catch则通过重新抛出将异常传递给更上层的函数进行处理;

double Division(int a, int b) {
	if (b == 0)
		throw "Division by zero condition!";
	else
		return (double)a / (double)b;
}

void Func() {
	int* array = new int[10];

	try {
		int len, time;
		cin >> len >> time;
		cout << Division(len, time) << endl; //如抛出异常,交由下面catch捕获
		cout << "delete []" << array << endl;
		delete[] array;
		return;
	}
	catch (...) {
		cout << "delete [] " << array << endl;
		delete[] array;
		throw; //没有完全处理Division(len, time)抛出的异常,需进一步校正,在向上抛异常
	}
}

int main() {
	try {
		Func();
	}
	catch (const char* errmsg) {
		cout << errmsg << endl;
	}
	return 0;
}

异常安全

  • 构造函数完成对象的构造和初始化,最好不要在构造函数中抛出异常;
    • 否则可能导致对象不完整或没有完全初始化;
  • 析构函数主要是完成资源的清理,最好不要在析构函数内抛出异常;
    • 否则可能导致资源泄露;
  • C++中异常经常导致资源泄露的问题,C++经常使用RAII来解决以上问题;
    • 如在new和delete中抛出了异常,导致内存泄露;
    • 在lock和unlock之间抛出了异常导致死锁;

异常规范

异常目的是为了让函数使用者知道该函数可能抛出的异常有哪些;

  • 可在函数的后面接throw(类型),列出这个函数可能抛出的所有异常类型;
  • 函数的后面接throw(),表示函数不抛异常;
  • 若无异常接口声明,则此函数可以抛出任何类型的异常;
// 这里表示这个函数会抛出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 new (std::size_t size, void* ptr) throw();

三,自定义异常体系

        实际使用中都会自定义自己的异常体系进行规范化的异常管理,如项目中大家随意抛异常,那么外层的调用者就会无从处理,所有实际中都会定义一套继承的规范体系,这样大家抛出的都是继承的派生类对象,由一个基类捕获即可;

// 服务器开发中通常使用的异常继承体系
class Exception {
public:
	virtual void info() = 0;
protected:
	string _errmsg;
	int _id;
	//list<StackInfo> _traceStack;
	// ...
};

class SqlException : public Exception {
public:
	void info() { cout << "SqlException" << endl; }	
};

class CacheException : public Exception {
public:
	void info() { cout << "CacheException" << endl; }
};

class HttpServerException : public Exception {
public:
	void info() { cout << "HttpServerException" << endl; }
};

int main() {
	try {
		// server.Start();
		// 抛出对象都是派生类对象
		throw HttpServerException();
	}
	catch (Exception& e) { // 由父类对象捕获
		e.info();
	}
	catch (...) {
		cout << "Unkown Exception" << endl;
	}
	return 0;
}

四,C++标准库的异常体系

        C++提供了一系列标准的异常,可在程序中使用这些标准的异常,它们是以父子类层次结构组织起来的;实际中可以去继承exception类来实现自己的异常类;

 

五,异常的优缺点

        与传统错误码对比;

优点

  • 定义好异常对象,相比错误码的方式可以清晰准确的展示出错误的各种信息,甚至可以包含堆栈调用的信息,这样可以帮助更好的定位程序的bug;
  • 返回错误码的传统方式有个很大的问题,在函数调用链中,深层的函数返回了错误,那么得层层返回错误,最外层才能拿到错误;
  • 很多的第三方库都包含异常,比如boost/gtest/gmock等常用的库,那使用它们也需要使用异常;
  • 很多测试框架都使用异常,这样就能更好的使用单元测试等进行白盒的测试;
  • 部分函数使用异常更好处理,如构造函数没有返回值,不方便使用错误码方式处理,如T& operator这样的函数,如pos越界了只能使用异常或终止程序处理,没办法通过返回值表示错误;

缺点

  • 异常会导致程序的执行流落跳,且非常混乱,运行时出错抛异常就会乱跳,这会导致跟踪调试时以及分析程序时比较困难;
  • 异常会有一些性能的开销,但在现代硬件速度下基本可忽略;
  • C++没有垃圾回收机制,资源需要自己管理,有了异常非常容易导致内存泄露,死锁等异常安全问题,需要使用RAII来处理;
  • C++标准库的异常体系定义的不够好,导致大家各自定义各自的异常体系,非常的混乱;
  • 异常尽量规范使用,否则后果不堪设想,随意抛异常,外层捕获的用户苦不堪言,所有异常规范有两点;
    • 一是抛异常类型都继承自一个基类;
    • 二是函数是否抛异常/抛什么异常,都使用func()、throw()的方式规范化;

磁传感器技术解析:从霍尔效应到车规级应用,纳芯微的本土第一之路 磁传感器是现代工业与汽车电子中的关键感知元件,其技术演进经历了从分立器件到高集成度SoC的跨越。霍尔效应与磁阻效应构成两大物理基础,其中硅基霍尔方案凭借高性价比与成熟供应链,在车规级应用中占据主流。高精度电流检测、角度与位置感知、磁开关等场景,对传感器的温漂抑制、共模瞬态抗扰与批量一致性提出严苛要求。车规级可靠性体系与系统级集成能力,成为衡量供应商的核心标尺。随着新能源主驱、光伏逆变、工业伺服等应用爆发,具备完整信号链与隔离技术积累的厂商正逐步构建护城河。本文以纳芯微为样本,剖析其从隔离技术延伸至磁传感器平 阅读详情

相关推荐

海思Hi3516平台集成IMX214 Sensor实战:从I2C调试到VI通路构建

本文详细记录了在海思Hi3516平台上集成索尼IMX214图像传感器的完整实战过程。从硬件I2C通讯调试、驱动层适配,到上层VI通路构建与ISP配置,提供了系统性的排查步骤与代码修改要点,旨在帮助开发者快速打通从Sensor到屏幕的完整视频采集链路,解决集成过程中的常见问题。

tcp8optimizer的博客 596

异常

在C语言中,传统的错误处理机制是这样子的: 终止程序,如****assert,缺陷:用户难以接受。如发生内存错误,除0错误时就会终止程序; 返回错误码,缺陷:需要程序员自己去查找对应的错误。如系统的很多库的接口函数都是通过把错误码放到errno中,表示错误 而大多数情况下,C语言都是通过返回错误码的方式来处理错误,部分情况下使用终止程序处理比较严重的错误。 异常概念 在C++中,提出了...

瞎子my的博客 569

树莓派使用 OLED 屏显示图片及文字

树莓派默认是不带显示屏的,如果想要查看系统的一些信息,需要使用电脑登录到树莓派,或者通过 HDMI 连接外接显示器查看。这样做总是有点麻烦,我们可以通过外接一个 OLED 屏来显示一些关键参数或者图片。本文将详细介绍操作方法。 OLED 模组介绍 OLED 屏主要有两种:128×32 和 128×64 ,主要颜色是白、黄、蓝。OLED 屏的特点是功耗低,价格便宜,使用 I2C 接口与主机连接。本文所使用的是 128×64 尺寸的屏幕,外形如下: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直

码到成功 3742

C++11 异常

在C++中,异常是程序在执行过程中遇到意外情况或错误时抛出的一种机制。当程序运行过程中发生异常,可以通过抛出异常、捕获异常和处理异常来改变程序的正常执行流程。

皮蛋的Bk 570

Ubuntu升级遇到grub-efi-amd64-signed安装失败?3步搞定这个烦人错误

本文深度解析Ubuntu系统升级时grub-efi-amd64-signed安装失败并提示“cannot find EFI directory”错误的根本原因。该错误通常由EFI系统分区挂载异常、BIOS/UEFI引导模式不匹配或dpkg包状态死锁导致。文章提供了三步精准修复流程:首先检查并修复ESP分区挂载,其次处理dpkg依赖问题,最后针对传统BIOS系统提供适配方案,帮助用户安全彻底地解决这一常见升级难题。

r7s8t的博客 398

PD详解 扩展消息——Source_Capabilities_Extended Message

PD的协议层分为控制消息,数据消息还有扩展消息,今天大师匈讲一下扩展消息中的source_cap_extended。这个消息在扩展消息中算是比较关键的东西。 扩展消息中的source_cap_extended 大师匈先上图,然后逐一解释; 上面的图表说了source_cap_ext中包含了哪些内容。 我们注意到在source_cap扩展消息中是以字节为单位的,并不是像source_cap中以一个object为单位,当然有注意到PD标准spec中说明的扩展消息的话,那里有说明,在header之后的字节

大师匈的博客 3516

【C++11 —— 异常】

实际使用中很多公司都会自定义自己的异常体系进行规范的异常管理,因为一个项目中如果大家随意抛异常,那么外层的调用者基本就没办法玩了,所以实际中都会定义一套继承的规范体系。这样大家抛出的都是继承的派生类对象,捕获一个基类就可以了。在软件开发中,尤其是复杂系统的开发中,使用自定义异常体系可以帮助团队规范化异常管理。通过定义一套继承体系,所有抛出的异常都是特定基类的派生类,这样外层调用者可以通过捕获基类来处理所有相关的异常。使用自定义异常可以提供更具体的错误信息,使得代码的可读性和可维护性得到提升。

jokr_的博客 1599

基于ESP32Cam摄像头+YOLOv3完成图像识别_355

本项目正是在此背景下提出,设计一个基于ESP32Cam摄像头的图像识别系统,通过WIFI热点通信实现图像数据的传输,并利用上位机(Windows与Android平台的QT APP)实时显示原始图像与识别结果,实现目标检测、识别与标注功能。

594

关于异常:类型最先匹配与异常对象拷贝

异常处理是这样一类机制,它允许我们在程序执行过程中遇到异常情况时处理这类突发事件,C++中使用throw关键字来抛出异常事件,被抛出的异常通过类型来区分,抛出的位置称为抛出点,其会被写入到异常变量中,而外层通过catch(类型)来捕获异常并处理。 其基本使用方式是通过 try{ .....throw() ...} catch( ){} 方式来在异常情况出现时,抛出异常和处理异常。 #include<iostream> using namespace std; class mal...

一只老风铃 572

16、SQL Server索引的创建与评估

本文详细介绍了SQL Server中索引的创建与评估方法,涵盖索引的基本概念、类型(聚集与非聚集)、唯一性设置以及如何判断索引的好坏。通过实际操作步骤、维护策略和常见问题解决方案,帮助数据库开发者合理设计索引,提升查询性能并控制维护开销。同时提供了索引创建与维护的决策流程图,便于理解和应用。

water的专栏 126

基于ResNet + LLM大语言模型的分类识别系统设计与实现,Web前后端分离,Django+vue3+AI助手模块+ResNet50算法+LLM 联动+Element Plus等技术,全网独发

分类识别任务是计算机视觉中的重要任务,广泛应用于智慧校园分类、智慧农业、智慧生活场景分类等领域。常见的分类模型有 VGGNet、ResNet 、MobileNet 、ConvNeXt、DenseNet、ViT、Swin Transformer、YOLOv8/11/26。本项目结合 ResNet分类识别算法 + LLM大语言模型联动 ,使用 Django + Vue3,构建了一个通用的 Web 前后端系统,用户端 + 管理端 ,便于用户操作检,不仅可以用于大论文的工作量展示,还可以作为毕业设计。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 756

[cpp进阶]C++异常

在实际使用中,我们会自定义异常体系进行规范的异常管理,因为一个项目中如果大家随意抛异常,那么外层的调用者没有办法识别异常是从哪一个业务层抛出的,所以实际中都会定义一套继承的规范体系。

weixin_53027918的博客 2967

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C++异常处理 进阶

标准异常不够用时,可以继承标准异常,创建自己的异常类,携带更多错误信息(错误码、错误位置、自定义描述等)。// 自定义异常:继承 runtime_errorprivate:// 自定义错误码public:// 构造函数// 获取错误码// 测试函数throw MyException("用户名不存在", 1001);cout << "异常信息:" << e.what() << endl;

堇荼如饴风禾尽起~ 474

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

《C++进阶之C++11》【异常】

本文介绍了C++11中的异常处理机制,通过try-catch-throw结构实现程序错误的捕获与处理。文章详细讲解了throw抛出异常、try监控代码块、catch捕获异常的语法规则和执行流程,并给出除法运算的异常处理示例

序属秋秋秋的博客 5705

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

C++进阶——异常

C++98中函数参数列表的后面接throw(),表示函数不抛异常,函数参数列表的后面接throw(类型1, 类型2...)表示可能会抛出多种类型的异常,可能会抛出的类型用逗号分割。,否则后面的5个资源就没释放,也资源泄漏了。如果是102号错误,这个异常不处理,出了catch子句,自动析构,再尝试发送。,这里由于异常就引发了资源泄漏,产生安全性的问题。,比如析构函数要释放10个资源,释放到第5个时抛出异常,则也。,前面申请了资源(内存、锁等),后面进行释放,但是。,(若没有移动构造,就调用拷贝构造)。

博客 | 复习知识点 + 练习 + 最终的领悟 | 全力以赴 991

【C++进阶】C++异常详解

但是因为一些原因,C++的异常体系设计的不是那么的好用,所以大多数都是我们自己去用第三方的库或者自己实现一个异常体系。实际使用中很多公司都会自定义自己的异常体系进行规范的异常管理,因为一个项目中如果大家随意抛异常,那么外层的调用者基本就没办法玩了,所以实际中都会定义一套继承的规范体系。这样大家抛出的都是继承的派生类对象,捕获一个基类就可以了。这里C++ 异常的讲解就到这里了,我们引出了智能指针的概念和RAII的概念,还是比较重要的,我会在下一节重点讲解。希望大家可以对异常能有个很好的理解。

weixin_64906519的博客 1284

C++进阶之异常

实际使用中很多公司都会自定义自己的异常体系进行规范的异常管理,因为一个项目中如果大家随意抛异常,那么外层的调用者基本就没办法玩了,所以实际中都会定义一套继承的规范体系。这样大家抛出的都是继承的派生类对象,捕获一个基类就可以了// 服务器开发中通常使用的异常继承体系protected:int _id;// ...{};{};{};int main()try{// 抛出对象都是派生类对象catch (const Exception& e) // 这里捕获父类对象就可以。

baobao1767640830的博客 857

C++进阶—异常

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

Awkwardx的博客 692

C++进阶:异常

虽然异常可以是任何类型,但在多人项目中,为了更好的合作与项目编写。对于异常往往是会有一套项目组内自定义的异常体系的,通常会先确定一个异常基类,里面包含着最基础的必须的异常信息,后续根据异常来源的不同,继承异常基类并添加新的异常信息。下面是一套常用于服务器开发的自定义异常体系逻辑。(服务器开发一般会分为网络层开发、缓存层开发、数据库层开发)服务器开发的自定义异常体系自定义异常使用的简单模拟场景。

qq_71806743的博客 908

[C++基础]039_C++异常处理初级出门+中级进阶

[C++基础]039_C++异常处理初级出门+中级进阶

Littleree的博客 78

c++进阶——异常

本文介绍了C++异常处理机制及其与C语言错误处理的区别。异常机制将错误检测与处理分离,通过throw抛出异常并由catch捕获。异常会沿着调用链寻找最近的匹配catch块,沿途对象会被自动销毁。文章重点讲解了异常捕获规则、栈展开过程及类型匹配原则,并指出通过继承体系可以实现更灵活的异常处理。相比C语言的错误码方式,C++异常机制能更有效地传递错误信息并保证程序稳定性。

2301_79705195的博客 683

C++进阶--异常

异常概念,抛出和捕获细节,异常的语法,异常如何使用

2402_87779153的博客 1091

【C++进阶】异常

【C++进阶】异常

2301_78022459的博客 955

C++进阶:异常

• 异常处理机制允许程序中独立开发的部分能够在运行时就出现的问题进行通信并做出相应的处理, 异常使得我们能够将问题的检测与解决问题的过程分开,程序的一部分负责检测问题的出现,然后解决问题的任务传递给程序的另一部分,检测环节无须知道问题的处理模块的所有细节。上面的代码就是在除以0时抛出异常,但是抛出异常后在Func函数里有资源需要释放,但是捕捉异常的特性就是直接跳到catch位置,这里的资源没法释放就会资源泄漏,所以这里我们套一个catch捕捉异常,先把资源释放掉再去throw抛异常,外部再去捕捉。

2301_81699364的博客 1143
上一篇: C++进阶 —— auto/decltype(C++11新特性)
下一篇: C++进阶 —— 智能指针
挨代码
博客等级 码龄5年 1696粉丝 384原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值