异常
本人不才,对于异常只能做基本的介绍,无法给出自己的体会以及无法指明易错点
C异常
c语言处理异常的方式有
assert
——直接中断程序
返回错误码
——需要查找错误码表确定错误
这两种操作都不是很好,如果一个大型程序,为了找到一个错误,加载都需要半天,一遍又一遍的运行调试,是不是就很耗时间
于是c++就有了异常处理机制
C++异常
c++异常做到了程序
自己检查异常,自己抛出异常,统一进行捕获
,最重要的就是程序不会挂掉
通常有三部:
try——确定可能发异常的代码片段
throw——抛出异常
catch——捕获异常
double div()
{
int a, b;
cin >> a >> b;
if (a == 0 && b == 0) throw(1);
else if (b == 0) throw("div发生除0错误");
else if (a == 3 && b == 3) throw(1.1);
else if (a == 4 && b == 4) throw(1, 'c');
return (double)a / b;
}
void test()
{
while (1)
{
try
{
cout << div() << endl;
}
catch (const char* s)
{
puts(s);
}
catch (int a)
{
printf("%d\n", a);
}
catch (char c)
{
printf("%d\n", c);
}
catch (...)
{
puts("未知异常");
}
}
}
一个throw只能抛出一个错误,一个catch也只能捕捉一个错误
else if (a == 4 && b == 4) throw(1, 'c');
上面代码中,throw并不是抛出两个,而是采用逗号表达式
的形式进行计算,最终抛出的是char
类型
异常的匹配规则
1.抛出什么类型,就是去找匹配的类型:int->int,char*->char*,char->char
这里的匹配是很严格的,int不会去找char,char也不会去找int(他们都可以转换成整型,他们都不相互串门,确实很严格)
2.抛出错误,往前找,找到最近的位置进行捕捉
在mian函数中添加try-catch,验证抛int异常
能不能再mian中捕捉到
double div()
{
int a, b;
cin >> a >> b;
if (a == 0 && b == 0) throw(1);
else if (b == 0) throw("div发生除0错误");
else if (a == 3 && b == 3) throw(1.1);
else if (a == 4 && b == 4) throw(1, 'c');
return (double)a / b;
}
void test()
{
while (1)
{
try
{
cout << div() << endl;
}
catch (int a)
{
printf("%d\n", a);
}
//catch (char c)
//{
// printf("%d\n", c);
//}
catch (...)
{
puts("未知异常");
}
}
}
int main()
{
try
{
test();
}
catch (int a)
{
puts("main");
}
return 0;
}
3.对于抛出错误,直接跳到捕捉位置,中间产生的函数栈帧会逐层进行回收,但是throw后的代码不会执行
double div()
{
int a, b;
cin >> a >> b;
if (a == 0 && b == 0) throw(1);
else if (b == 0) throw("div发生除0错误");
else if (a == 3 && b == 3) throw(1.1);
else if (a == 4 && b == 4) throw(1, 'c');
puts("---");
return (double)a / b;
}
没有执行div函数中的puts
异常安全
1.不要再
构造函数
内部抛异常
2.不要在析构函数
内抛异常
异常规范
使用
noexcept
关键字表示这个函数不会抛出异常,如果抛出异常会进行报警——这中方式比较强硬
也可以使用throw(...)
再括号中可以添加任意多个类型,添加在某个函数之后,表示这个函数可以抛出的错误类型;不写表示不会抛出,但是如果抛出了也不会报错
标准异常库
再引入
execption
库之后就可以使用库中的类了
只需要写一句,就可以捕捉类中
所能抛出的所有异常
,并使用what函数进行打印
throw invalid_argument("b=0");
catch (const exception& e)
{
cout << e.what() << endl;
}
重中之重
1.异常规范有两点:
一、抛出异常类型都继承自一个基类
。
二、函数是否抛异常、抛什么异常,都使用 func() throw();
的方式规范化。
2.异常可能造成内存泄漏,人们为了解决这个问题就产生了——智能指针