C++ -- 异常

news2024/7/7 16:22:50

文章目录

  • 1. C语言传统处理
  • 2. C++异常概念
  • 3. 异常的使用
    • 3.1 异常抛出并没有被捕获
    • 3.2 正确使用
    • 3.3 捕获异常采用类型匹配就近原则
    • 3.4 catch(...)可以捕获任意类型异常
    • 3.5 抛出派生类对象使用基类捕获
    • 3.6 异常重新抛出
    • 3.7 匹配规则
    • 3.8 异常规范
    • 3.9 异常安全
  • 4. 自定义异常体系
  • 5. 异常优缺点
    • 5.1 优点
    • 5.2 缺点

1. C语言传统处理

  1. assert()函数直接终止程序。弊端:用户难以接受
  2. 返回错误码。弊端:需要程序员自己去查找对应的错误

2. C++异常概念

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

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

3. 异常的使用

3.1 异常抛出并没有被捕获

#include <iostream>
using namespace std;

double division(int x, int y)
{
	if (y == 0)
		throw "division by zero condition!";
	return (double)x / (double)y;
}

void test()
{
	int x, y;
	cin >> x >> y;
	division(x, y);
}

int main()
{
	test();
	return 0;
}
//输入:1 0
//程序直接终止

3.2 正确使用

#include <iostream>
using namespace std;

double division(int x, int y)
{
	if (y == 0)
		throw "division by zero condition!";
	return (double)x / (double)y;
}

void test()
{
	int x, y;
	cin >> x >> y;
	try
	{
		division(x, y);
	}
	catch (const char* message)
	{
		cout << message << endl;
	}
}

int main()
{
	test();
	return 0;
}

3.3 捕获异常采用类型匹配就近原则

#include <iostream>
using namespace std;

double division(int x, int y)
{
	if (y == 0)
		throw "division by zero condition!";
	return (double)x / (double)y;
}

void test()
{
	int x, y;
	cin >> x >> y;
	try
	{
		division(x, y);
	}
	catch (const char* message)
	{
		cout << "test()" << endl;
		cout << message << endl;
	}
}

int main()
{
	try
	{
		test();
	}
	catch (const char* message)
	{
		cout << "main()" << endl;
		cout << message << endl;
	}
	return 0;
}
//输入:1 0
//输出:
//test()
//division by zero condition!
#include <iostream>
using namespace std;

double division(int x, int y)
{
	if (y == 0)
		throw "division by zero condition!";
	return (double)x / (double)y;
}

void test()
{
	int x, y;
	cin >> x >> y;
	try
	{
		division(x, y);
	}
	catch (char message)
	{
		cout << "test()" << endl;
		cout << message << endl;
	}
}

int main()
{
	try
	{
		test();
	}
	catch (const char* message)
	{
		cout << "main()" << endl;
		cout << message << endl;
	}
	return 0;
}
//输入:1 0
//输出:
//main()
//division by zero condition!

3.4 catch(…)可以捕获任意类型异常

#include <iostream>
using namespace std;

double division(int x, int y)
{
	if (y == 0)
		throw "division by zero condition!";
	return (double)x / (double)y;
}

void test()
{
	int x, y;
	cin >> x >> y;
	try
	{
		division(x, y);
	}
	catch (...)
	{
		cout << "test()" << endl;
	}
}

int main()
{
	try
	{
		test();
	}
	catch (const char* message)
	{
		cout << "main()" << endl;
		cout << message << endl;
	}
	return 0;
}
//输入:1 0
//输出:
//test()

3.5 抛出派生类对象使用基类捕获

#include <iostream>
using namespace std;

class Exception
{
protected:
	int _code; //错误码
	std::string _message; //错误信息
public:
	Exception(int errcode, const std::string& errmessage)
		:_code(errcode)
		,_message(errmessage)
	{}
	~Exception() {}

	int getErrcode() const
	{
		return _code;
	}
	
	const string& getMessage() const
	{
		return _message;
	}
};

class DivisionException : public Exception
{
private:
	typedef Exception Base;
public:
	DivisionException(int errcode, const std::string& errmessage)
		:Base(errcode, errmessage)
	{}

	~DivisionException() {}
};
double division(int x, int y)
{
	if (y == 0)
		throw DivisionException(1, string("division by zero condition!")); 
	return (double)x / (double)y;
}

void test()
{
	int x, y;
	cin >> x >> y;
	try
	{
		division(x, y);
	}
	catch (const Exception& exception)
	{
		cout << "errcode:" << exception.getErrcode() << endl << "errmessage:" << exception.getMessage() << endl;
	}
}

int main()
{
	test();
	return 0;
}

3.6 异常重新抛出

#include <iostream> 
using namespace std;

double division(int x, int y)
{
	if (y == 0)
		throw "division by zero condition!";
	return (double)x / (double)y;
}

void test()
{
	int x, y;
	cin >> x >> y;
	try
	{
		division(x, y);
	}
	catch (const char* message)
	{
		cout << "test()" << endl;
		cout << message << endl;
		throw;
	}
	catch (...)
	{
		cout << "unknown exception!" << endl;
	}
}

int main()
{
	try
	{
		test();
	}
	catch (...)
	{
		cout << "main()" << endl;

	}
	return 0;
}
//输入:1 0
//输出
//test()
//division by zero condition!
//main()

3.7 匹配规则

  1. 异常是通过抛出对象而引发的,该对象的类型决定了应该激活哪个catch的处理代码。
  2. 被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个。
  3. 抛出异常对象后,会生成一个异常对象的拷贝,因为抛出的异常对象可能是一个临时对象,所以会生成一个拷贝对象,这个拷贝的临时对象会在被catch以后销毁。
  4. catch(…)可以捕获任意类型的异常
  5. 实际中抛出和捕获的匹配原则有个例外,并不都是类型完全匹配,可以抛出的派生类对象,使用基类捕获
  6. 没有匹配的catch则退出当前函数栈,继续在调用函数的栈中进行查找匹配的catch。如果到达main函数的栈,依旧没有匹配的,则终止程序

3.8 异常规范

  1. 异常规格说明的目的是为了让函数使用者知道该函数可能抛出的异常有哪些
  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;

3.9 异常安全

  1. 构造函数完成对象的构造和初始化,最好不要在构造函数中抛出异常,否则可能导致对象不完整或没有完全初始化
  2. 析构函数主要完成资源的清理,最好不要在析构函数内抛出异常,否则可能导致资源泄漏
  3. new/malloc/fopen/lock等都可能会导致资源泄露问题

4. 自定义异常体系

#include <iostream>
#include <string>
#include <thread>
using namespace std;

class Exception
{
protected:
	int _code; //错误码
	std::string _message; //错误信息
public:
	Exception(int errcode, const std::string& errmessage)
		:_code(errcode)
		,_message(errmessage)
	{}
	~Exception() {}
public:
	int getErrcode() const
	{
		return _code;
	}
	
	const string& getMessage() const
	{
		return _message;
	}

	virtual std::string what() const
	{
		return std::to_string(_code) + _message;
	}
};


class SQLException : public Exception
{
private:
	typedef Exception Base;
private:
	std::string _SQLstatement; //SQL语句错误
public:
	SQLException(int errcode, const std::string& errmessage, const string& SQLstatement)
		:Base(errcode, errmessage)
		,_SQLstatement(SQLstatement)
	{}
	~SQLException() {}
public:
	virtual string what() const
	{
		string message = "SQLException:" + std::to_string(_code) + " " + _message + "->" + _SQLstatement;
		return message;
	}
};

class CacheException : public Exception
{
private:
	typedef Exception Base;
public:
	CacheException(int errcode, const std::string& errmessage)
		:Base(errcode, errmessage)
	{}
	~CacheException() {}
public:
	virtual string what() const
	{
		string message = "CacheException:" + std::to_string(_code) + " " + _message;
		return message;
	}
};

class HttpServerException : public Exception
{
private:
	typedef Exception Base;
private:
	std::string _type; //错误类型
public:
	HttpServerException(int errcode, const std::string& errmessage, const std::string& errtype)
		:Base(errcode, errmessage)
		,_type(errtype)
	{}
	~HttpServerException() {}
public:
	virtual string what() const
	{
		string message = "HttpServerException:" + std::to_string(_code) + " " + _message + "->" + _type;
		return message;
	}
};

void SQL()
{
	srand(time(0));
	if (rand() % 7 == 0)
	{
		throw SQLException(7, "permission denied", "select * from name = '张三'");
	}
    cout << "success" << endl;
}

void cache()
{
	srand(time(0));
	if (rand() % 5 == 0)
	{
		throw CacheException(5, "permissiong denied");
	}
	else if (rand() % 6 == 0)
	{
		throw CacheException(6, "data do not exsit");
	}
	SQL();
}

void httpServer()
{
	srand(time(nullptr));
	if (rand() % 3 == 0)
		throw HttpServerException(3, "Request insufficient resources", "get");
	if (rand() % 4 == 0)
		throw HttpServerException(4, "permission denied", "post");
	cache();
}

void test()
{
	while (true)
	{
		std::this_thread::sleep_for(std::chrono::seconds(1));

		try
		{
			httpServer();
		}
		catch (const Exception& exception)
		{
			cout << exception.what() << endl;
		}
		catch (...)
		{
			cout << "unknown exception!" << endl;
		}
	}
}

int main()
{
	test();
	return 0;
}

5. 异常优缺点

5.1 优点

  1. 相比错误码的方式可以清晰准确的展示出错误的各种信息,甚至可以包含堆栈调用的信息,这样可以帮助更好的定位程序的bug
  2. 很多的第三方库都包含异常,比如boost、gtest、gmock等等常用的库,那么我们使用它们也需要使用异常
  3. 部分函数使用异常更好处理,比如构造函数没有返回值,不方便使用错误码方式处理。比如T& operator这样的函数,如果pos越界了只能使用异常或者终止程序处理,没办法通过返回值表示错误

5.2 缺点

  1. 异常会导致程序的执行流乱跳,并且非常的混乱,并且是运行时出错抛异常就会乱跳
  2. 异常会有一些性能的开销。当然在现代硬件速度很快的情况下,这个影响基本忽略不计。
  3. C++没有垃圾回收机制,资源需要自己管理
  4. C++标准库的异常体系定义得不好,导致大家各自定义各自的异常体系,非常的混乱
  5. 异常尽量规范使用,否则后果不堪设想,随意抛异常,外层捕获的用户苦不堪言

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

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

相关文章

05.动态协议OSPF基础

文章目录 **OSPF简介****OSPF和RIP的区别****RIPV2和OSPFV2相同点****不同点** OSPF基础概念OSPF区域OSPF路由类型区域划分的要求**OSPF多区域****Router ID****Router ID选取规则****度量值** OSPF数据包OSPF状态机条件匹配 OSPF的工作过程OSPF基本配置**OSPF的拓展配置** OSP…

番外12:获取晶体管漏极电流源平面的仿真波形

番外12&#xff1a;获取晶体管漏极电流源平面的仿真波形 老是有同学反应&#xff0c;仿真中无法获取漏极电流源平面的仿真波形&#xff0c;在此给出解释与解决办法。 1、ADS能够访问到部分器件的电流源平面波形 对于某些器件&#xff0c;比如说CGH40010F&#xff0c;可以在仿…

硬核了解一下内核链表

一&#xff0c;内核链表定义 言以蔽之&#xff0c;内核链表就是个带头结点的循环双链表。 普通的链表是将next指针定义成为与该结构体一样的类型&#xff0c;这样做通用性不好。与普通的链表的定义和使用方式不一样&#xff0c;内核的链表定义成为了一种通用的结构&#xff1a…

vue打包到生产环境

1.进入到项目根目录执行 npm run build此时会自动打包在dist目录下 2.安装服务 npm install -g serve3.启动 serve dist以上是生产环境打包的过程。 npm run dev 是开发环境, npm run build 是生产环境

Springboot 错用list.stream , 遭遇list浅拷贝偷袭,实战图解

前言 相信很多看客都听闻过深拷贝、浅拷贝 &#xff0c; 但是在日常使用的过程中&#xff0c;是否真的有关心过或者遭遇过呢&#xff1f; 不啰嗦&#xff0c;一起来看看。 正文 接下来我通过示例&#xff0c;来复现一下 list.stream浅拷贝 这个事 &#xff1a; 首先是一个对象…

Nacos服务注册成功,RestTemplate调用服务提供者时空指针异常(已解决)

发现问题并进行记录 目录 项目场景&#xff1a;问题描述原因分析解决 项目场景&#xff1a; RestTemplate也可以做服务调用(进行测试) 目的:解决该问题,不考虑其他远程调用方式(Fegin,Dubbo) 项目Pom文件 Spring Boot ----2.6.3 Spring Cloud------2021.0.1 Spring Cloud Al…

Elasticsearch介绍和安装

ELK简介 Elastic Stack核心产品包括Elasticsearch、Logstash、Kibana&#xff08;也称为ELK&#xff09;和Beats等等。能够安全可靠地获取任何来源、任何格式的数据&#xff0c;然后实时地对数据进行搜索、分析和可视化 Kibana是一个免费且开放的用户界面&#xff0c;能…

Apikit 自学日记:可以对 API 发评论

该功能仅供API研发管理企业版 您可以直接在API文档上发布评论&#xff0c;所有的沟通内容都会跟随API文档保留下来并且按照版本分类好&#xff0c;而不是零散地存在各种聊天工具中。 发表评论 在API详情页&#xff0c;点击 评论 按钮&#xff0c;在弹窗中可以输入评论信息并点…

FPGA实验一:层次法设计组合电路(加法器)

目录 一、实验目的 二、实验要求 三、实验代码 四、实验结果及分析 1、引脚锁定 2、仿真波形及分析 3、下载测试结果及分析 五、实验心得 一、实验目的 &#xff08;1&#xff09;掌握基本组合逻辑电路的 FPGA实现&#xff1b; &#xff08;2&#xff09;学习 Verilo…

使用安装器安装windows gcc— MinGW及让windows像Linux一样的MSYS

这里使用installer进行安装GCC&#xff0c;主要是installer安装其它依赖&#xff0c;如MSYS&#xff0c;autoconf,automake&#xff0c;libtool&#xff0c;vim,perl,mingw-developer-toolkit等&#xff0c;mingw下载地址&#xff0c;如图download链接的mingw-get-setup.exe文件…

高级端口扫描工具

高级端口扫描程序可查看哪些服务在哪个端口上运行、开放端口数量、连接的交换机&#xff0c;并帮助保护网络免受未经授权的访问。作为网络管理员&#xff0c;扫描网络中的开放端口、这些端口已连接到的交换机以及在其上运行的服务&#xff0c;并将已知服务与已识别的服务与高级…

迁移学习入门,新手该如何下手?

推荐迁移学习技术的实用入门图书:《自然语言处理迁移学习实战》 [加纳] 保罗阿祖雷&#xff08;Paul Azunre&#xff09; 著&#xff0c;李想&#xff0c;朱仲书&#xff0c;张世武 译 一本书带你读懂ChatGPT背后的技术&#xff0c;自然语言处理迁移学习&#xff0c;解锁机器学…

Xcode Build System

Xcode Build System iOS开发者都使用Xcode来开发、编译程序&#xff0c;但是我们真正了解xcode是怎样编译我们的程序到手机上的么&#xff0c;下面我们主要看看xcode的编译系统内容 一、Preprocessor 预处理&#xff1a;在此步骤中xcode会处理代码中的宏&#xff0c;将其展开…

19k字图文讲解Vision科研常用的系统环境配置和工具(附详细命令行)

猛码Memmat | 转载请注明来源 最近作者有了新设备,趁更新系统写一篇博客为小白讲解这一入门过程 目录 ArchLinux 安装指南(新手向)前言准备工作检查网络通过 SSH 远程连接(可选)硬盘分区格式化并挂载分区设置中国镜像源(推荐)安装系统系统初始化设置进阶设置设置交换空…

VScode中的插件

开启VScode中最简单的内部浏览器 - 可以访问外网 - Browser Preview 插件安装&#xff1a; 插件使用&#xff1a;由下角 - 状态栏 - VS Browser按钮 live sass compiler-vscode插件将scss编译为css live sass compiler是VSCode扩展&#xff0c;可以实时地将SASS / SCSS文件…

基于Spring Boot的智慧社区系统设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频&#xff1a; https://www.bilibili.com/video/BV1kF411R7Tp/?vd_sourced8d0eebf6c94c5aa49fe3f992c8887b0使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 后端&#xff1a;Java springboot框架 myba…

Django搭建图书管理系统01

Django框架 Django是一个使用Python编写的开源Web应用程序框架。它采用了MVC&#xff08;Model-View-Controller&#xff09;的软件设计模式&#xff0c;旨在简化开发复杂的Web应用程序。 以下是Django框架的一些主要特点&#xff1a; 强大的开发工具&#xff1a;Django提供了…

计算机毕业论文内容参考|基于Python的入侵检测系统的设计与实现

文章目录 导文摘要前言绪论课题背景国内外现状与趋势课题内容相关技术与方法介绍系统分析系统设计系统实现系统测试总结与展望导文 计算机毕业论文内容参考|基于Python的入侵检测系统的设计与实现 摘要 本文介绍了基于Python的入侵检测系统的设计与实现。首先,简要概述了入侵…

ubuntu中使用docker部署mysql

docker images&#xff1a;查看已有镜像docker pull mysql&#xff1a;拉取镜像docker ps -a&#xff1a;查看已有容器docker -o mysql8.0.33.tar&#xff08;保存镜像使用的名称&#xff09; mysql&#xff08;被保存的镜像&#xff09;&#xff1a;避免重复下载&#xff0c;可…

CMU 15-445 -- Tree Indexes - 05

CMU 15-445 -- Tree Indexes - 05 引言Table IndexB TreeB-Tree FamilyB TreeB Tree NodesB Tree OperationsIn Practice Clustered IndexesCompound IndexB Tree Design ChoicesNode SizeMerge ThresholdVariable Length KeysNon-unique IndexesIntra-node Search Optimizatio…