文章目录
catch块的顺序
上一篇文章说了对于一组有继承关系的异常类,catch块的顺序。现在说下其他情况下的顺序。
完全不知道会引发什么异常
确实有这种情况存在。比如你写了一个函数,调用了别人写的一个函数,你不清楚别人的这个函数可能会引发什么异常。
这时候,可以在catch的括号中写省略号,表示任何异常类型,就可以捕捉任何类型的异常。
catch (```)
{
···
}
知道一部分可能引发的异常
可以把自己知道的可能的异常写在前面,然后把省略号表示的任何类型的异常写在最后,就像switch语句的default语句一样嘚。当然前面那些异常如果有继承关系,也要按照祖先类在后孩子类在前的顺序。
try{
duper();
}
catch (bad_3 & be){
···
}
catch (bad_2 & be){
···
}
catch (bad_1 & be){
···
}
catch(```){
//catch whatever is left
···
}
如果catch参数是类的对象,不是类的引用,会怎样?
即按值传递。当然啦,传回来的只是throw的对象的副本,因为按值传递嘛。
那么捕获到的就是对象的副本,不再是对象的副本的引用,这时候,如果catch参数是基类对象,则所有派生类的对象仍然会被捕捉,但是却不再可以派生,所以catch块内只能使用虚方法的基类版本,而没办法使用派生类自己的版本。
引用真是有用,原来按引用传递才能维持继承关系。
exception类
C++的库定义了很多从exception类派生来的异常类。这些类的名称指出了他们报告的错误类型。
stdexcept头文件
这个头文件定义了从exception类公有派生来的logic_error
类和runtime_error
类。这两个类成为了两大派生类系列的基类。即异常类大致分为两大派系,分别由logic_error
类和runtime_error
类派生出去。
如果这两个类以及他们派生的类还是没办法解决你的问题,你可以自己从logic_error
类和runtime_error
类中派生一个异常类,自己来写。从他俩中派生是为了保证你的异常也在继承层次中,catch块的顺序好放。
可以看到,这几个类的构造函数都接受一个string引用参数。
logic_error
类:描述典型的逻辑错误,这类错误可以通过编程修复
从logic_error
类派生出来的异常类有:
domain_error
类:domain,是定义域的意思。range表示值域。
当数学函数的参数不在此函数的定义域内时,引发这个异常。比如std::asin()反正弦函数,定义域是-1到+1,如果输入参数不在这个范围,就引发异常。
我试了试
cout << std::asin(2);
应该是引发了异常,异常被捕捉到,catch块的操作是返回非数值。只不过没有打印有关异常的任何信息而已,实际上asin函数的库版本一定是用了异常处理的。
nan
invalid_argument
类: 传递的参数无效,比如函数只要0或1,你传2,就会引发。length_error
类:没有足够空间就会引发。比如,string类的append方法,合并两个string对象时,得到的串的长度如果超出了最大允许长度(?),就会引发。out_of_bounds
类:指示索引错误。比如数组下标不对。
这些错误,平时也多多少少都见过。
runtime_error
类:这类异常是无法避免的问题
从runtime_error
类派生出来的异常类有:
overflow_error
:当整型和浮点型的计算结果超出自己类型能表示的最大范围时候,就会引发上溢异常。underflow_error
类:只发生在浮点数的计算中,整型不会遇到这个问题。计算结果比浮点类型能够表示的最小非零值还要小的时候,就会引发。range_error
类:计算结果没有上溢也没下溢,但是不在函数允许的范围内,就引发。
bad_alloc异常类:也从exception类公有派生而来,处理new分配内存失败的错误
C语言malloc函数,以及C++以前的new运算符,分配内存失败返回一个空指针,后来C++改用异常处理,C还是返回空指针。
示例
//main.cpp
#include <iostream>
#include <string>
#include <new>
#include <cstdlib> //exit()函数
struct Big{
double stuff[20000];
};
int main()
{
Big * p;
try{
p = new Big[10000];//1.6GB
std::cout << "Got past the new request: \n";
}
catch (std::bad_alloc & ba){
std::cout << "Caught the exception!\n";
std::cout << ba.what() << std::endl;
exit(EXIT_FAILURE);
}
std::cout << "Memory successfully allocated!\n";
p[0].stuff[0] = 4;
std::cout << p[0].stuff[0] << std::endl;
delete [] p;
return 0;
}
Got past the new request:
Memory successfully allocated!
4
double stuff[20000];
Caught the exception!
std::bad_array_new_length
Process returned 1 (0x1) execution time : 0.337 s
Press any key to continue.
我和书上返回的字符串不一样啊。
和空指针方案兼容的方法(不太好使?)
书上还说,为了和以前的空指针方案兼容,毕竟有很多代码已经那么写了。于是C++标准提供了一个开关,让用户来选择到底用哪一种方案。
代码:
//main.cpp
#include <iostr