longjmp和setjmp
setjmp(buff)返回值是0,设置long的跳转点,setjmp执行完后,内部会将当前程序所有的寄存器信息和数据保存到buff中
#include <setjmp.h>
jmp_buf buff;
void Func1()
{
FILE* pf = fopen("1111.txt", "rb");
if (nullptr == pf)
{
longjmp(buff, 1);
}
// ...
fclose(pf);
}
void Func2()
{
char* p = (char*)malloc(0x7fffffff);
if (nullptr == p)
{
longjmp(buff, 2);
}
// ...
free(p);
}
int main()
{
// 在设置程序的跳转点,
// setjmp执行完成之后,会把当前位置的寄存器信息会保存到buff中
// 然后setjmp返回0
int istate = setjmp(buff);
if (0 == istate)
{
// 执行程序的正常逻辑
Func2();
Func1();
}
else
{
// 错误处理
switch (istate)
{
case 1:
cout << "Func1中的fopen打开文件失败" << endl;
break;
case 2:
cout << "Func2中的malloc申请空间失败" << endl;
break;
default:
cout << "为止错误" << endl;
break;
}
}
return 0;
}
异常
- throw: 当问题出现时,程序会抛出一个异常
错误发生后,不想在函数体内处理,想让函数的调用者处理,或者调用的调用者处理
throw 后可以跟数字,变量,对象- catch: 捕获异常,可以有多个catch进行捕获
捕获throw后跟的东西
catch(int err)
类似于函数的形参- try: try 块中的代码标识将被激活的特定异常,它后面通常跟着一个或多个 catch 块。
new运算符的operator new函数中,有一个_RAIS宏,内部封装了throw
vector中的at函数会抛出异常
- 异常是按照类型捕获的,
throw 1
是抛出整形异常,异常编号是1,异常不会发生类型转换
对所有可能抛出异常的代码都要捕获- 有异常被抛出,如果当前存在异常的函数没有捕获,则异常会从函数中出来,进入调用者的作用域,被最近的匹配的类型捕获
- 抛出的异常是一个临时对象,这个临时对象被catch后销毁
-异常的重新抛出:catch(...)
捕获任意异常,捕获到异常后,不处理它又再次抛出- 抛子类的异常,可以在catch中用父类对象接收
栈展开:异常被抛出后,没有在本函数内捕获,会逐层抛给调用者,直到被捕获
异常安全
由异常引起的安全问题
不要在构造和析构中抛异常,这样可能导致对象初始化和释放的不完整
异常规范
使func3函数只能抛整形异常
括号中不写,表示函数不能抛出异常,否则编译失败
基本不抛内置类型异常
直接抛exception类对象,重写父类的what方法,调用what方法就知道哪个子类有问题了
不同子类对象含义不一样