学习C++:异常处理

举报
AI 菌 发表于 2021/08/05 01:54:54 2021/08/05
【摘要】 1.导致异常的原因 异常可能是外部因素导致的,如系统没有足够的内存;也可能是应用程序内部因素导致的,如使用的指针包含无效值或除数为零。为向调用者指出错误,有些模块引发异常。 异常会打断应用程序的正常流程。毕竟,如果没有内存可用,应用程序就无法完成分配给它的任务。然而应用程序可处理这种异常:向用户显示一条友好的错误消息,采取必要的挽救措施并妥善地退出。 2.使用try...

1.导致异常的原因

异常可能是外部因素导致的,如系统没有足够的内存;也可能是应用程序内部因素导致的,如使用的指针包含无效值或除数为零。为向调用者指出错误,有些模块引发异常。
异常会打断应用程序的正常流程。毕竟,如果没有内存可用,应用程序就无法完成分配给它的任务。然而应用程序可处理这种异常:向用户显示一条友好的错误消息,采取必要的挽救措施并妥善地退出。

2.使用try和catch捕获异常

要捕获语句可能引发的异常,可将它们放在try块中,并使用catch块对try块可能引发的异常进行处理,语法如下:

void Func()
{
	try
	{
		int* pNumber = new int;
		*pNumber = 999;
		delete pNumber;
	}
	catch(...)
	{
		cout<<"Exception in Func, quiting"<<endl;
	}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

(1)使用catch(…)处理所有异常
成功分配内存时,默认形式的new返回一个指向该内存单元的有效指针,但失败时引发异常。下面将演示如何捕获使用new分配内存时可能引发的异常,并在计算机不能分配请求的内存时进行处理。

#include <iostream>
using namespace std;

int main()
{
	cout<<"输入要存储的整数的个数:";
	try
	{
		int Input = 0;
		cin>>Input;
		int* pRInts = new int [Input]; //自动分配内存空间
		delete[] pRInts;
	} 
	catch(...)   //...捕获所有类型的异常
	{
		cout<<"Got to end, sorry!"<<endl;
	}
	return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在此程序中,如果键盘输入的Input为一个负数,这显然不符合要求。如果没有异常处理,该程序将以讨厌你的方式终止。但由于有异常处理程序,程序将显示一条友好的消息:Got to end, sorry!结束程序。

(2)捕获特定类型的异常
一般的异常的类型是已知的,为了查明导致异常的原因,执行更有针对性的清理工作,或者至少是向用户显示一条提示消息,这时就可以选择捕获这种类型的异常。
其实上面(1)中的程序,当键盘输入指定存储的个数为负数时,将导致引发异常,而该异常类型为std::bad_alloc。
下面程序将演示捕获std::bad_alloc类型的异常:

#include <iostream>
#include <exception>
using namespace std;

int main()
{
	cout<<"输入要存储的整数的个数:";
	try
	{
		int Input = 0;
		cin>>Input;
		int* pRInts =new int [Input];
		delete[] pRInts;
	}
	catch(std::bad_alloc& exp)  //捕获类型为bad_alloc的异常,这种异常由new引发
	{
		cout<<"Exception encountered: "<<exp.what()<<endl; //描述导致异常的原因
		cout<<"Got to end, sorry!"<<endl;
	}
	catch(...)  //获未被其他catch块显示捕获的所有异常
	{
		cout<<"Got to end, sorry!"<<endl;
	}
	return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

3.使用throw引发特定类型的异常

在上面演示的程序中,捕获std::bad_alloc时,实际上是捕获new引发的std::bad_alloc类对象。你也可以引发自己选择的异常,为此只需要使用关键字throw。语法如下:
void Func()
{
if(case_unwanted)
throw Value;
}
当做除法运算时,若除数为0将导致程序异常。下面将演示如何使用throw引发这种自定义异常:

#include <iostream>
using namespace std;

double Divide(double Dividend, double Divisor)
{
	if (Divisor == 0)
		throw "Divisor should not be zero!";
	return (Dividend / Divisor);
}
int main()
{
	cout << "Enter Dividend: ";
	double Dividend = 0;
	cin >> Dividend;
	cout << "Enter Divisor: ";
	double Divisor = 0;
	cin >> Divisor;

	try
	{
		cout << "Dividend/Divisor=" << Divide(Dividend, Divisor);
	}
	catch(const char* exp) //捕获类型为char*的异常,于是可调用函数Divide()中可能引发的异常throw
	{
		cout << "Exception: " << exp << endl;
		cout << "Sorry, can't continue!" << endl;
	}
	return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

注意:上述代码没有将整个main()都放在try{}中,而只在其中包含可能引发异常的代码。提倡这种做法,因为异常处理也可能降低代码的执行性能。

4.std::exception类

捕获std::bad_alllocl类型异常时,实际上是捕获new引发的std::bad_alloc对象。std::bad_alloc继承了C++标准类std::exception,而使用exception类时,需要添加头文件:#include
从std::exception派生出来的几个重要的异常类:
bad_alloc: 使用new请求内存失败时引发
bad_cast: 试图使用dynamic_cast转换错误类型时引发
ios_base::failure: 由iostream库中的函数和方法引发

std::exception是异常基类,定义了虚函数what(),用来描述导致异常的原因。
因为std::exception是众多异常类型的基类,所以所有将std::exception作为基类的异常,均可使用catch(const exception&)捕获:

void Func()
{
	try
	{
		// code made exception safe
	}
	catch(const std::exception& exp)
	{
		cout<<"导致异常的原因是:"<<exp.what()<<endl;
	}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

从std::exception派生出自定义异常类
让自定义异常继承std::exception的好处在于,现有的异常处理程序catch(const std::exception)不但能捕获bad_alloc、bad_cast等异常,还能捕获自定义异常,因为它们的基类都是exception。
下面将演示继承std::exception的CustomException类:

#include <exception>
#include <iostream>
#include <string>
using namespace std;

class CustomException : public std::exception
{
	string Reason;
public:
	CustomException(const char* why) :Reason(why) {}

	virtual const char* what() const throw()
	{
		return Reason.c_str();
	}
};

double Divide(double Dividend, double Divisor)
{
	if (Divisor == 0)
		throw CustomException("CustomException: Divisor should not be zero!");
	return (Dividend / Divisor);
}

int main()
{
	double Dividend = 0, Divisor = 0;
	cout << "Enter Dividend: ";
	cin >> Dividend;
	cout << "Enter Divisor: ";
	cin >> Divisor;
	try
	{
		cout << "Dividend/Divisor=" << Divide(Dividend, Divisor);
	}
	catch (exception& exp) //不但处理异常CustomException,还处理bad_alloc等其他以exception为基类的异常
	{
		cout << "导致异常的原因:"<<exp.what()<<endl;
		cout << "Sorry,cant't continue!" << endl;
	}
	return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

文章来源: ai-wx.blog.csdn.net,作者:AI 菌,版权归原作者所有,如需转载,请联系作者。

原文链接:ai-wx.blog.csdn.net/article/details/104318449

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。