C++实现并优化异常系统
目录
- 一、模拟栈展开的过程
- 二、新异常处理系统中异常的定义
- 三、超级运用
文章图片
调用what()方法时只返回异常的名称,并没有显示抛出异常的位置和堆栈跟踪,功能上显得少许的贫瘠...
下面这个是我自己实现的改良版的异常处理系统:
文章图片
可以看到详细的信息,下面是实现过程。
一、模拟栈展开的过程 网上看到别人用一些很奇怪的方法来获取堆栈信息,从而实现堆栈跟踪。
个人觉得很费劲,而且还要安装第三方库。
【C++实现并优化异常系统】于是我们可以写一个类来模拟这个过程。
定义一个叫做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) { }}; templateclass 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 a = 128; a[129] = new char[16]; est.pop(); return 0; }
结果:
文章图片
为一的遗憾就是没法加上行号文件等提示信息,如果能够实现的话,我将会在下一篇博客中提及。
到此这篇关于C++实现并优化异常系统的文章就介绍到这了,更多相关C++异常系统内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- go源码分析——类型
- 做新媒体月薪轻松突破2万,她说实现财务自由你也可以做得到!
- python|计算聚类系数clustering coefficient的python实现
- C++中红黑树实现详解
- C语言实现静态版通讯录的示例代码
- 利用Java实现文件锁定功能
- Flutter|Flutter GetPageRoute实现嵌套导航学习
- android|android studio实现上传图片到java服务器
- vue|Vue+springboot前后端分离实现简单的注册登录
- 理论基础——Java|实现前后端分离