文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2022-11-13 13:52

关注

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++异常系统内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯