18. 异常
异常:错误,意料之外的情况
常见的错误处理方法:
1.全局错误码
给每个错误定义一个错误码,赋值给全局变量
int n_gError
例如C语言库和windows编程的GetLastError()
缺点:维护困难
2.函数返回值
例如成功返回0,失败返回1...
缺点:函数调用层次多时,内层函数调用出错,错误码返回外层比较难设计。
例如调用链A->B->C->D->E,E错出错了,要依次返回到A
3.异常
int main() { throw 1;//如果异常没有被处理,最终会调用abort(),Debug版还会弹窗 cout << "asdf"; return 0; }
int main() { //类型必须精确匹配,不会隐式转换 try { throw 1;//1是int类型 } catch (unsigned i) {//类型不匹配 cout << i; } catch (double d) {//类型不匹配 cout << d; } //最终没有被捕获,调用abort() return 0; }
int main() { try { throw 1; cout << 1234;//不会执行这句,因为上面抛出了异常,之前的结果有问题,继续使用则可能发生问题 } catch (int i) { cout << i; } catch (...) {//捕获任何类型异常 } cout << 5678;//会执行,因为异常已经处理了 return 0; }
构造析构中抛出异常:
class A { public: A() { cout << "A" << endl; //throw 1;//构造函数中抛异常,不会调用析构函数 } ~A() { throw 1; cout << "~A" << endl;//不走catch块,直接调用abort() } }; int main() { try { A a;//离开try,进入catch时会调用析构函数 throw 1; cout << 1234;//不会执行这句,因为上面抛出了异常,之前的结果有问题,继续使用则可能发生问题 } catch (int i) { cout << i; } return 0; }
异常常用模式:从父类异常继承
class ExceptionInfo { public: ExceptionInfo(string file, string func, int line, string msg) : fileName(file), funcName(func), lineNumber(line), errorMsg(msg) {} string GetFileName()const { return fileName; } string GetFuncName()const { return funcName; } size_t GetLineNumber()const { return lineNumber; } string GetErrorMsg()const { return errorMsg; } private: string fileName; string funcName; size_t lineNumber; string errorMsg; }; class AddOverflowExceptionInfo :public ExceptionInfo { public: AddOverflowExceptionInfo(string file, string func, int line, string msg) : ExceptionInfo(file, func, line, "加法溢出") { } private: }; void f() { throw AddOverflowExceptionInfo(__FILE__, __func__, __LINE__, "错误"); } int main() { try { f(); } catch (const ExceptionInfo & e) { cout << e.GetFileName() << endl << e.GetFuncName() << endl << e.GetLineNumber() << endl << e.GetErrorMsg() << endl; } return 0; }