C++ day33 异常(二)exception类

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值