C++异常处理:当一个函数发现自己无法处理的错误时抛出异常,让函数的调用者直接或间接的处理这个问题
1.异常的抛出与捕获
- 异常是通过抛出对象引发的,该对象的类型决定了应该激活哪个处理代码
- 被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个
void FunTest()
{
FILE* fp = fopen("1.txt","rb");
if(NULL==fp)
{
//throw 1;
throw '1';
}
int *p = (int*)malloc(0x7fffffff/4);
if(p==NULL)
{
fclose(fp);//此时fp不为NULL,退出前关闭文件
throw 2;
}
fclose(fp);//此时fp,p都不为NULL
free(p);
}
int main()
{
try
{
FunTest();
}
catch(int a)
{
switch(a)
{
case 1:
cout<<"a"<<" "<<a<<"打开文件错误"<<endl;
break;
case 2:
cout<<"a"<<" "<<a<<"开辟空间出错"<<endl;
break;
}
}
catch(char)
{
cout<<"错误"<<endl;
}
getchar();//输出 a 1打开文件错误
return 0;
}
- 抛出异常后会释放局部存储对象所以被抛出的对象也就还给系统了,throw表达式会初始化一个抛出特殊的异常对象副本异常对象由编译器管理,异常对象在传给catch处理之后撤销
{
FILE* fp = fopen("1.txt","rb");
if(NULL==fp)
{
char a = '1';
cout<<(int*)&a<<endl;
throw a;
}
fclose(fp);
}
int main()
{
try
{
FunTest();
}
catch(char ret)
{
cout<<(int*)ret<<endl;
cout<<"文件打开错误"<<endl;
}
getchar();//打印的地址不相同
return 0;
}
2.栈展开
抛出异常处理对象的时候,将暂停当前函数的执行,开始查找对应的匹配catch语句。首先检查throw本身是否在try块内部,如果是在查找匹配的catch语句,如果有匹配,则处理;没有则退出当前函数栈,继续在调用函数的栈中进行查找;不断重复上述的过程。若到达main函数的栈,依旧没有匹配,则终止程序。上述这个沿用着调用链查找匹配的catch子句的过程称为栈展开
找到匹配的catch语句子句并处理后,会继续沿用着catch子句后面继续执行
void FunTest1()
{
FILE* fp = fopen("1.txt","rb");
if(fp==NULL)
{
throw 1;
}
fclose(fp);
}
void FunTest2()
{
try
{
FunTest1();
}
catch(...)
{
throw;
}
}
void FunTest3()
{
try
{
FunTest2();
}
catch(int)
{
cout<<"文件打开错误"<<endl;
}
}
int main()
{
FunTest3();
getchar();
return 0;
}
3.异常捕获的匹配规则
异常对象的类型与catch说明符的类型必须完全匹配,只有以下几种情况例外
- 允许从非const对象到const的转换
- 允许从派生类到基类类型的转换
将数组转换为指向数组类型的指针,将函数转换为指向函数类型的指针
4.有可能单个的catch不能完全处理的异常,再进行一些乔正后,希望能交个外层调用函数链来处理,ctach则可以通过重新抛出将异常传递给更上层的函数处理
void FunTest1()
{
throw 1;
}
void FunTest2()
{
int *p = new int[10];
FunTest1();
Delete[] p;//因为没有捕获,造成内存的泄露
}
int main()
{
FunTest2();
return 0;
}
//解决上述问题的方法
void FunTest2()
{
int *p = new int[10];
try
{
FunTest1();
}
catch(...)//获取但不关心,不解决错误,留给上级调用函数解决
{
delete[] p;
throw;
}
Delete[] p;
}
//解决不能获取错误码程序崩溃的方法
void FunTest()
{
int *p = new int[0x7fffffff/4];
throw 1;
}
int main()
{
try
{
FunTest();
}
//catch(int)//不能获取,程序直接崩溃
//{
// cout<<"失败"<<endl;
//}
catch(...)
{
cout<<"失败"<<endl;//虽然没有解决该问题,但是保证函数的运行不会崩溃
}
return 0;
}