C++实现并优化异常系统

 更新时间:2022年08月01日 09:26:20   作者:阿莫·西林  
异常处理是C++的一项语言机制,用于在程序中处理异常事件,下面这篇文章主要给大家介绍了关于C++中异常的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

C++原本的异常系统是这个样子的:

调用what()方法时只返回异常的名称,并没有显示抛出异常的位置和堆栈跟踪,功能上显得少许的贫瘠...

下面这个是我自己实现的改良版的异常处理系统:

可以看到详细的信息,下面是实现过程。

一、模拟栈展开的过程

网上看到别人用一些很奇怪的方法来获取堆栈信息,从而实现堆栈跟踪。

个人觉得很费劲,而且还要安装第三方库。

于是我们可以写一个类来模拟这个过程。

定义一个叫做ExceptionStackTrace的类:

class ExceptionStackTrace {
private:
	const char** m_message_trace = nullptr; // 方法名数组
	size_t* m_line_trace = nullptr; // 行数数组
	int m_top; // 栈顶
    int m_size; // 大小
public:
	ExceptionStackTrace(int size);
	void push(const char* message); // 入栈一个方法
	void pop(); // 出栈一个方法
	bool empty() const; // 判断是否为空
	int top() const; // 返回栈顶索引
    int size() const; // 返回大小
	void print_stack_trace() const; // 打印堆栈跟踪信息
	void throw_(SuperException except); // 抛出一个异常,需要继承SuperException这个后面会讲到
};

既然是模拟,所以需要在程序最前面定义一个静态的对象,使用时在每一个函数的开始和结束部分加上这两句:

static ExceptionStackTrace est = 128;
void method(...) {
	est.push(__FUNCSIG__);
    ... // 异常抛出在这里可以被捕捉
	est.pop();
}
main ...

当调用方法时,会在调用ExceptionStackTrace的push方法,将方法信息压栈。

之后再执行方法内部的语句。

最后在将方法出栈,模拟方法已被调用完毕。

下面是实现代码:

ExceptionStackTrace::ExceptionStackTrace(int size) {
    // 尺寸不能是负数
	if (size <= 0) throw std::exception("Size should greater than 0.");
	m_message_trace = new const char*[size];
	m_top = 0;
	m_size = size;
}
void ExceptionStackTrace::push(const char* message) {
    // 方法信息压栈
	m_message_trace[m_top] = message;
	++m_top;
}
void ExceptionStackTrace::pop() {
    // 方法信息出栈,栈空抛异常
	if (this->empty()) throw std::exception("Exception stack trace empty!");
	--m_top;
}
bool ExceptionStackTrace::empty() const {
	return m_top == 0;
}
int ExceptionStackTrace::top() const {
	return m_top;
}
int ExceptionStackTrace::size() const {
	return m_size;
}
void ExceptionStackTrace::print_stack_trace() const {
    // 从后往前,因为栈的性质后进先出
	for (int i = m_top - 1; i >= 0; --i) {
		printf("   At method \"%s\"\n", m_message_trace[i]);
	}
}
void ExceptionStackTrace::throw_(SuperException except) {
    // 抛出一个异常
	printf("Unhandled exception: %s: %s\n", except.exception_name(), except.message());
	this->print_stack_trace();
	exit(-1);
}

二、新异常处理系统中异常的定义

异常包括信息和异常名称,同时还需要支持自定义异常。

所以我们可以搞一个用于新异常系统的父类异常,自定义的异常全部继承这个类即可。

父类的名字叫SuperException,下面是类结构:

#define M_GetName(data) #data // 宏定义,获取字符串形式类的名称
class SuperException {
private:
	const char* m_exception_name = nullptr; // 异常名称
	const char* m_message = nullptr; // 异常消息
public:
    // 构造函数
	SuperException(const char* message, const char* exception_name = M_GetName(SuperException));
	const char* message() const; // 获取异常消息
	const char* exception_name() const; // 获取异常名称
};

然后是实现部分:

SuperException::SuperException(const char* message, const char* exception_name) {
	m_message = message;
	m_exception_name = exception_name;
}
const char* SuperException::message() const {
	return m_message;
}
const char* SuperException::exception_name() const {
	return m_exception_name;
}

具体用法:

int main() {
	est.push(__FUNCSIG__);
	int i = 0;
	scanf_s("%d", &i);
	if (i == 128) est.throw_(SuperException("这是一个异常。"));
	est.pop();
	return 0;
}

当输入128时:

三、超级运用

#include "ExceptionStackTrace.h"
static ExceptionStackTrace est = 128;
// 自定义一个异常
class IndexOutOfBoundsException : public SuperException {
public:
	IndexOutOfBoundsException(const char* message, const char* exception_name = M_GetName(Exception))
		: SuperException(message, exception_name) {
	}
};
// 自定义一个异常
class BadArrayException : public SuperException {
public:
	BadArrayException(const char* message, const char* exception_name = M_GetName(Exception))
		: SuperException(message, exception_name) {
	}
};
template<typename T> class Array {
private:
	T* m_array;
	size_t m_length;
private:
    // 下标检查
	void index_check(size_t index) {
		est.push(__FUNCSIG__);
		if (index >= m_length) {
			est.throw_(IndexOutOfBoundsException("Index out of bounds."));
		}
		est.pop();
	}
public:
    // 构造器
	Array(size_t length) {
		est.push(__FUNCSIG__);
		m_length = length;
		try {
			m_array = new T[length];
		} catch (std::bad_alloc) {
			est.throw_(BadArrayException("Cannot create a Array object because no space."));
		}
		est.pop();
	}
    // 索引访问
	T& operator[](size_t index) {
		est.push(__FUNCSIG__);
		index_check(index);
		est.pop();
		return m_array[index];
	}
};
int main() {
	est.push(__FUNCSIG__);
	Array<void*> a = 128;
	a[129] = new char[16];
	est.pop();
	return 0;
}

结果:

为一的遗憾就是没法加上行号文件等提示信息,如果能够实现的话,我将会在下一篇博客中提及。

到此这篇关于C++实现并优化异常系统的文章就介绍到这了,更多相关C++异常系统内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言实现九大排序算法的实例代码

    C语言实现九大排序算法的实例代码

    这篇文章主要给大家介绍了关于C语言实现九大排序算法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • C++求四个正整数最大公约数的方法

    C++求四个正整数最大公约数的方法

    这篇文章主要介绍了C++求四个正整数最大公约数的方法,涉及C++求余算法的运用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2016-05-05
  • C++ 数据结构 堆排序的实现

    C++ 数据结构 堆排序的实现

    这篇文章主要介绍了C++ 数据结构 堆排序的实现的相关资料,需要的朋友可以参考下
    2017-06-06
  • C/C++实现获取系统时间的示例代码

    C/C++实现获取系统时间的示例代码

    C 标准库提供了 time() 函数与 localtime() 函数可以获取到当前系统的日历时间。本文将通过一些简单的示例为大家讲讲C++获取系统时间的具体方法,需要的可以参考一下
    2022-12-12
  • C语言也有封装,继承和多态你知道吗

    C语言也有封装,继承和多态你知道吗

    这篇文章主要为大家详细介绍了C语言封装,继承,多态,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • C++ OpenCV制作哈哈镜图像效果

    C++ OpenCV制作哈哈镜图像效果

    这篇文章主要介绍了使用OpenCV C++ 制作哈哈镜图像特效。其原理就是让图像像素扭曲,将像素重新进行映射。感兴趣的可以跟随小编一起试一试
    2022-01-01
  • C/C++实现发送与接收HTTP/S请求的示例代码

    C/C++实现发送与接收HTTP/S请求的示例代码

    HTTP(Hypertext Transfer Protocol)是一种用于传输超文本的协议,它是一种无状态的、应用层的协议,用于在计算机之间传输超文本文档,通常在 Web 浏览器和 Web 服务器之间进行数据通信,本文给大家介绍了C/C++发送与接收HTTP/S请求,需要的朋友可以参考下
    2023-11-11
  • C语言零基础精通变量与常量

    C语言零基础精通变量与常量

    这篇文章主要为大家详细介绍了C语言的变量和常量,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-04-04
  • 基于matlab MFCC+GMM的安全事件声学检测系统

    基于matlab MFCC+GMM的安全事件声学检测系统

    这篇文章主要为大家介绍了基于matlab MFCC+GMM的安全事件声学检测系统实现及源码示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2022-02-02
  • C++中std::transform的使用小结

    C++中std::transform的使用小结

    std::transform 是 C++ 标准库中的一个算法,本文主要介绍了C++中std::transform的使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-05-05

最新评论