赞
踩
传统的错误处理机制
//setjmp和longjmp的使用例子 #include<malloc.h> #include<setjmp.h> //该全局变量中将来保存的是longjmp函数的跳转的位置 jmp_buf buff;//由setjmp来设置buff的跳转信息 void Test1() { char* p = (char*)malloc(0x7ffffffff); if (nullptr == p) { //一但申请空间失败时,longjmp会跳转到buff对应的位置。 longjmp(buff,1); } ///正常操作 } void Test2() { FILE* pf = fopen("2222.txt", "rb"); if (nullptr == pf) { longjmp(buff, 2); } //... fclose(pf); } int main() { //setjmp设置longjmp函数的跳转点 //注意:setjmp在首次调用时,一定会返回0 int iState = setjmp(buff); if (0 == iState) { //正常操作 Test1(); Test2(); } else{ //程序遇到非法情况,longjmp跳转到switch //一般情况:写的程序的错误处理 switch (iState) { case 1: cout << "malloc申请空间失败" << endl; break; case 2: cout << "打开文件失败" << endl; break; default: cout << "未知错误" << endl; break; } } return 0; }
int main()
{
https://www.baidu.com;
return 0;
}
如果用longjmp
,必须setjmp
设置跳转点,否则buff为0,代码崩溃。
上述代码可以通过编译,编辑器把https://www.baidu.com
当成网址来识别,编译器把https://www.baidu.com
当成注释来处理。https:
相当于标签,//
后面为注释
异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的直接或间接的调用者处理这个错误。
void Test() { FILE* pf = fopen("2222.txt", "rb"); if (nullptr == pf) { throw 1; } //... //进行常规的文件操作 fclose(pf); } int main() { try { Test(); } catch (int e) { //错误处理流程 cout << e << endl; } system("pause"); return 0; }
void Test() { FILE* pf = fopen("2222.txt", "rb"); if (nullptr == pf) { throw 1; } //... //进行常规的文件操作 fclose(pf); } void Test2() { char* p = (char*)malloc(0x7ffffffff); if (nullptr == p) { throw 1.0; } ///正常操作 } int main() { try { Test2(); Test(); } //异常按照类型捕获,一般不会进行类型转换的 catch (int e) { //捕获所有int类型的异常 //错误处理流程 cout << e << endl; } catch (double e) { //捕获double类型的异常 cout << e << endl; } system("pause"); return 0; }
void Test() { FILE* pf = fopen("2222.txt", "rb"); if (nullptr == pf) { throw 1; } //... fclose(pf); } void Test2() { int *p = new int[10]; //.... try{ //距离异常抛出位置比较进,所以优先捕获,主函数捕获不到 Test(); } catch (int e) { delete[]p; cout << e << endl; return; } } int main() { try { Test(); Test2(); } catch (int e) { cout << e << endl; } system("pause"); return 0; }
void Test() { int a = 10; cout << &a << endl; //在抛异常时,并不是将a本身抛出,而是抛出了a的一个副本 throw a; } int main() { try { Test(); } catch (int& ra) { cout << &ra << endl; } system("pause"); return 0; }
class A { public: A() { cout << "A::A()" << this << endl; } A(const A&a) { cout << "A::A(const A&a)" << this<<endl; } ~A() { cout << "A::~A()" << this << endl; } }; void Test() { A a; cout << &a << endl; //在抛异常时,并不是将a本身抛出 throw a;//实际抛得是a得副本 } int main() { try { Test(); } catch (A& ra) { cout << &ra << endl; } system("pause"); return 0; }
4. catch(…)可以捕获任意类型的异常,问题是不知道异常错误是什么。
int main() { try { Test(); } /*catch (A& ra) { cout << &ra << endl; }*/ catch (...)//万能捕获 { cout << "A" << endl; } system("pause"); return 0; }
class Exception { public: Exception(const string& errInfo,int errNo) :_errInfo(errInfo) , _errNo(errNo) {} virtual void What() = 0; protected: string _errInfo; int _errNo; }; class NetException : public Exception { public: NetException(const string& errInfo, int errNo) :Exception(errInfo,errNo) {} virtual void What() { cout << _errInfo << ":" << _errNo << endl; } }; class DBException : public Exception { public: DBException(const string& errInfo, int errNo) :Exception(errInfo, errNo) {} virtual void What() { cout << _errInfo << ":" << _errNo << endl; } }; //通过网络传递数据 void Test1() { NetException e("网络中断", 40); throw e; } //操作数据库 void Test2() { DBException e("数据库未打开", 500); } int main() { try { Test1(); Test2(); } catch (Exception&e)//按照基类的方式进行捕获 { e.What(); } system("pause"); return 0; }
有可能单个的catch不能完全处理一个异常,在进行一些校正处理以后,希望再交给更外层的调用链函数来处理,catch则可以通过重新抛出将异常传递给更上层的函数进行处理。
void Test() { FILE* pf = fopen("2222.txt", "rb"); if (nullptr == pf) { throw 1; } //... fclose(pf); } void Test2() { int *p = new int[10];//new 也会抛异常,operator new申请空间失败,如果没有相应的措施,抛异常 //.... try{ Test(); } catch (...) { //1.假设Test2现在根本不知道Test1抛出异常的类型 //2.如果Test2知道Test1所抛异常的类型,但是Test2没有必要必须要解决Test1抛出的异常 delete[]p; throw ; } delete[]p; } int main() { try { Test2(); } catch (int e) { cout << e << endl; } system("pause"); return 0; }
//Test()抛异常,只能抛出整型的异常
//否则:在编译期间就会报错
void Test1()throw(int)
{
throw 1;
}
//该函数一定不会抛出异常,
//否则:在编译期间就会报错
void Test2()throw()
{
}
一个项目中如果大家随意抛异常,那么外层的调用者基本就没办法玩了,所以实际中都会定义一套继承的规范体系。这样大家抛出的都是继承的派生类对象,捕获一个基类就可以了
class Exception { public: Exception(const string& errInfo,int errNo) :_errInfo(errInfo) , _errNo(errNo) {} virtual void What() = 0; protected: string _errInfo; int _errNo; }; class NetException : public Exception { public: NetException(const string& errInfo, int errNo) :Exception(errInfo,errNo) {} virtual void What() { cout << _errInfo << ":" << _errNo << endl; } }; class DBException : public Exception { public: DBException(const string& errInfo, int errNo) :Exception(errInfo, errNo) {} virtual void What() { cout << _errInfo << ":" << _errNo << endl; } }; //通过网络传递数据 void Test1() { NetException e("网络中断", 40); throw e; } //操作数据库 void Test2() { DBException e("数据库未打开", 500); } int main() { try { Test1(); Test2(); } catch (Exception&e)//按照基类的方式进行捕获 { e.What(); } system("pause"); return 0; }
实际中我们可以可以去继承exception类实现自己的异常类
// 1.下面这段伪代码我们可以看到ConnnectSql中出错了,先返回给ServerStart,ServerStart再返回 //给main函数,main函数再针对问题处理具体的错误。 // 2.如果是异常体系,不管是ConnnectSql还是ServerStart及调用函数出错,都不用检查,因为抛出的 //异常异常会直接跳到main函数中catch捕获的地方,main函数直接处理错误。 int ConnnectSql() { // 用户名密码错误 if (...) return 1; // 权限不足 if (...) return 2; } int ServerStart() { if (int ret = ConnnectSql() < 0) return ret; int fd = socket() if(fd < 0) return errno; } int main() { if(ServerStart()<0) ... return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。