目录
1. c语言传统处理错误的方法
2. c++异常的概念
3.异常的使用
4.c++标准库的异常体系
5.异常的优缺点
(1) 终止程序: assert, 非常之暴力,直接终止进程, 不管是否轻重的异常.
(2) 返回错误码: 需要对错误码进行查找.
(1) 当函数无法处理的错误的时候就可以抛异常, 让函数直接/间接调用的操作者进行修改错误.
(2) 一般会采用到三个关键字来处理: 看代码更好理解
throw:
当程序异常的时候, 就会抛出异常.
catch:
用于进行异常捕获.
try:
被激活异常的条件.
(1) 异常的抛出和匹配原则:
被选中处理代码是与最近的那一个进行匹配的.
抛出异常之后, 会产生一个异常对象的拷贝, 在catch之后被销毁.
(2) 采用的原则:
先检查throw是否在try里面, 再匹配合适的catch;
如果没用合适的catch就会退出当前函数栈,如果到达main函数的栈,依旧没有匹配的,则终止程序。
- class A
- {
- public:
- A()
- {
- cout << "A()" << endl;
- }
-
- ~A()
- {
- cout << "~A()" << endl;
- }
- };
-
- double Division(int len, int time)
- {
- if (time == 0)
- {
- throw "除0错误";
- }
- else
- {
- return (double)len / (double)time;
- }
- }
-
- void Func()
- {
- A aa;
- try
- {
- int len, time;
- cin >> len >> time;
- cout << Division(len, time) << endl;
- }
- catch(const char* s)
- {
- cout << s << endl;
- }
-
- cout << ">>>>>>>>>>>>>>" << endl;
- }
-
- int main()
- {
- try
- {
- Func();
- }
- catch (const char* str)
- {
- cout << str << endl;
- }
- return 0;
- }
处理一些可能当个catch无法完成的异常, 通过重新抛异常交给上层函数进行处理.
- double Division(int len, int time)
- {
- if (time == 0)
- {
- throw "除0错误";
- }
- else
- {
- return (double)len / (double)time;
- }
- }
-
- void Func()
- {
- int* arry = new int[10];
- try
- {
- int len, time;
- cin >> len >> time;
- cout << Division(len, time) << endl;
- }
- catch (...) //... 表示的是到这里说明有人没有按规范(约定)抛异常
- {
- cout << "delete []" << arry << endl;
- delete[] arry;
- throw;
- }
- }
-
- int main()
- {
- try
- {
- Func();
- }
- catch (const char* errmsg)
- {
- cout << errmsg << endl;
- }
- return 0;
- }
最好不要再构造函数和析构函数里面调用异常函数; 因为构造函数在完成对象的构造和初始化的时候被中断, 造成对象不完整或者没有初始化.
析构函数也是在完成对对象内存的销毁不完整和没有销毁导致内存泄漏的危险.
(1) 如果要抛出某种类型的异常; 函数()后面 + throw(类型);
(2) 如果不抛出异常; 函数()后面 + throw();
(3) 关键字noexcept, 加在函数后面就是不需要抛异常.
- class Execption
- {
- public:
- Execption(const string& errmsg, int id)
- :_errmsg(errmsg)
- ,_id(id)
- {}
-
- virtual string what()const
- {
- return _errmsg;
- }
-
- protected:
- string _errmsg;
- int _id;
- };
-
- class SqlExecption : public Execption
- {
- public:
- SqlExecption(const string& errmsg, int id, const string& sql)
- :Execption(errmsg, id)
- ,_sql(sql)
- {}
-
- virtual string what()const
- {
- string str = "SqlExecption:";
- str += _errmsg;
- str += "->";
- str += _sql;
- return _sql;
- }
-
- private:
- const string _sql;
- };
-
- class CacheException : public Execption
- {
- public:
- CacheException(const string& errmsg, int id)
- :Execption(errmsg, id)
- {}
-
- virtual string what() const
- {
- string str = "CacheException:";
- str += _errmsg;
- return str;
- }
- };
-
- class HttpServerException : public Execption
- {
- public:
- HttpServerException(const string& errmsg, int id, const string& type)
- :Execption(errmsg, id)
- , _type(type)
- {}
-
- virtual string what() const
- {
- string str = "HttpServerException:";
- str += _type;
- str += ":";
- str += _errmsg;
-
- return str;
- }
-
- private:
- const string _type;
- };
-
- void SQLMgr()
- {
- srand(time(0));
- if (rand() % 7 == 0)
- {
- throw SqlExecption("权限不足", 100, "select * from name = '张三'");
- }
- }
-
- void cacheMgr()
- {
- srand(time(0));
- if (rand() % 5 == 0)
- {
- throw CacheException("权限不足", 100);
- }
- else if (rand() % 6 == 0)
- {
- throw CacheException("数据不存在", 101);
- }
-
- SQLMgr();
- }
-
- void HttpServer()
- {
- // ...
- srand(time(0));
- if (rand() % 3 == 0)
- {
- throw HttpServerException("请求资源不存在", 100, "get");
- }
- else if (rand() % 4 == 0)
- {
- throw HttpServerException("权限不足", 101, "post");
- }
-
- cacheMgr();
- }
这里用一下其他博主的图. 实际中是继承了exception的类来实现自己的异常类
- int main()
- {
- try
- {
- vector<int> v(10, 5);
- //v.resize(100000000);
- v.at(10) = 100;
- }
- catch(const exception& e)
- {
- cout << e.what() << endl;
- }
- catch (...)
- {
- cout << "Unkown Exception" << endl;
- }
- return 0;
- }
异常为invalid vector subscript(无效的矢量下标).
(1) 相比于错误码更加清晰的可以看出来异常的信息, 更好的找到bug.
(2) 返回错误码的操作需要跳到最外层才可以拿到错误信息, catch直接跳出函数到main函数处理错误.
(3) 很多第三方库都是使用到异常.
(4) 部分函数适合使用异常, 比如有些函数是没有返回值; 例如构造函数, 还有越界处理.
(1) 异常会导致程序执行乱跳, 非常混乱. 就会难以调试.
(2) c++没有垃圾回收机制, 如果有些资源在catch之前没有回收就会导致资源泄漏. 可以使用RAII来处理资源的管理问题
(3) 使用异常的使用最好要规范:
首先就是抛出异常类型都是继承来一个类; 其次就是函数抛异常, 抛声明异常最好写清楚.