异常处理

来源:互联网 发布:电脑测温软件 编辑:程序博客网 时间:2024/05/18 00:28

计算机应用程序中离不开错误处理,尤其是生产型大型软件系统。应用软件系统运行属于循环处理事务,出错后需要保证不能让软件程序直接退出。这就需要使用一定的程序容错处理来应对。一般情况下,大型软件开发中的软件系统容错处理会结合异常处理、错误代码定义的使用与相应的出错处理日志记录,包括一定的参与大型生产系统的监控系统等配合保障系统的稳定性。下面本章将会就C++软件系统中提供的异常处理作详细的讲述,包括基本概念以及应用操作情况。
14.1 C++异常处理简介
软件应用程序中,异常处理机制是一种比较有效的处理系统运行时错误的方法。C++针对异常处理提供了一种标准的方法,用于处理软件程序运行时的错误,并用于处理软件系统中可预知或不可预知的问题。这样就可以保证软件系统运行的稳定性与健壮性。
C++中异常的处理主要用于针对程序在运行时刻出现错误而提供的语言层面的保护机制。它允许开发者最大限度地发挥,针对异常处理进行相应的修改调整。
C++应用程序中在考虑异常设计时,并不是所有的程序模块处理都需要附加上异常情况的处理。相对来说,异常处理没有普通方法函数调用速度快。过度的错误处理会影响应用程序运行的效率。通常在C++开发的软件系统中,应用程序都由对应的库、组件以及运行的具体不同模块组成。在设计时,异常的处理应充分考虑到独立程序库以及组件之间的情况。便于使用者在程序出现异常情况下,使用库或者组件的开发者能够快速定位出库、组件还是应用程序的错误。
由于大型软件系统中库与组件通常都是以独立的程序方式提供给具体设计开发模块人员。开发人员通常不了解组件与库中具体实现情况,只是根据提供的接口来操作使用。在不清楚具体库与组件的具体实现情况下,开发者可能在极端的情况下操作应用库或者组件提供的方法。此时相应的异常处理通信就会成为必不可少的错误处理通信机制。下面将会就C++语言提供的异常机制支持作详细应用讲述,在实践中总结异常应用的场合与具体实现方法。
14.2 C++异常处理方法
C++语言异常部分的支持也是在后续语言发展中逐步讨论并添加的内容。该语言针对异常处理提供了一系列的语法支持。C++语言除了提供异常的关键字语法支持以外,其标准库中支持异常处理而封装异常类也很好的为应用程序中异常处理判断使用提供直接的帮助。
14.2.1 C++异常处理:try、throw与catch
C++语言中针对异常处理提供了三个关键字,分别为try、throw与catch。C++应用程序中通过这三个关键字实现机制组合来实现异常的处理。下面通过常见异常处理操作方式来介绍应用程序中使用异常处理关键字的基本方式,其基本语法定义如下所示。
try
{
… //可能出错产生异常的代码
throwtypen();
}catch(type1)
{
… //对应类型的异常处理代码
}catch(type2)
{
… //对应类型的异常处理代码
}
… //更多类型异常处理代码
或者
try
{
function();//调用可能会抛出异常的函数方法
}catch(type1)
{
… //对应类型的异常处理代码
}catch(type2)
{
… //对应类型的异常处理代码
}

C++应用程序中,try关键字后的代码块中通常放入可能出现异常的代码。随后的catch块则可以是一个或者多个;catch块主要用于异常对应类型的处理。try块中代码出现异常可能会对应多种异常处理情况,catch关键字后的圆括号中则包含着对应类型的参数。
try块中代码体作为应用程序遵循正常流程执行。一旦该代码体中出现异常操作,会根据操作的判断抛出对应的异常类型。随后逐步的遍历catch代码块,此步骤与switch控制结构有点相像。当遍历到对应类型catch块时,代码会跳转到对应的异常处理中执行。如果try块中代码没有抛出异常,则程序继续执行下去。
try体中可以直接抛出异常,或者在try体中调用的函数体中间接的抛出。下面将会通过一个简单的异常处理实例,来使用C++语言中支持的异常处理方式。
1.准备实例
打开UE工具,创建新的空文件,并且另存为chapter1401.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示。
/**
* 实例chapter1401
* 源文件chapter1401.cpp
* 简单异常处理
*/

include

include

using namespace std;

int main()
{
try
{
intvalue1,value2; //定义两个整型变量
cout<<”Pleaseinput two value:”<

include

include

using namespace std;

void divideCompute(int value1,int value2) //除法计算函数定义
{
if(value1== 0) //如果被除数为0,则抛出参数类型为浮点型异常
{
throw0.0;
}
elseif(value2 == 0) //如果除数为0,则抛出参数类型为整型异常
{
throw0;
}
else //否则执行除法运算并打印输出结果
{
cout<<”value1/value2:”<<(value1/value2)<

include

include

using namespace std;

void divideCompute(int value1,int value2) //除法计算函数定义
{
if(value2== 0) //如果除数为0,则抛出相应的整型异常
{
throw0;
}
else //否则计算除法运算,并打印结果
{
cout<<”value1/value2:”<<(value1/value2)<

include

include

using namespace std;

void divideCompute(int value1,int value2)
{
try
{
if(value2== 0) //如果除数为0,则抛出异常
{
throw0; //抛出整型异常
}
else //否则计算除法运算
{
cout<<”value1/value2:”<<(value1/value2)<

ifndef EXCEPTION_H_

define EXCEPTION_H_

include

include

using namespace std;
//自定义异常类
class MyException
{
public:
//异常类无参数默认构造函数定义
MyException()
{
m_context= “”; //初始化异常信息数据成员为空
}
//异常类空析构函数定义
~MyException(){}
//异常类字符串类型参数构造函数定义
MyException(const string & right)
{
m_context= right; //初始化异常信息数据为字符串对象参数
}
//异常类字符串指针类型参数构造函数定义
MyException(const char * right)
{
m_context= right; //初始化异常信息数据为字符串指针参数
}
//异常类返回异常信息接口方法定义
stringwhat() const
{
returnm_context; //直接返回相应的异常信息数据成员
}
private:
string m_context; //字符串类型数据成员,表示异常信息
};

endif

//异常测试类,除法计算类头文件chapter1405_02.h

include “chapter1405_01.h”

//自定义除法计算类
class Compute
{
public:
Compute(intvalue1,int value2); //除法计算类构造函数,两个整型参数列表
~Compute(){} //除法计算类空析构函数定义
voiddivideCompute(); //除法计算类除法计算方法成员
private:
intm_value1; //除法计算类数据成员,表示被除数
intm_value2; //除法计算类数据成员,表示除数
};
//异常测试类,除法计算类源文件chapter1405_02.cpp

include “chapter1405_02.h”

Compute::Compute(int value1,int value2) //除法计算类构造函数定义
{
m_value1= value1; //初始化被除数数据成员
m_value2= value2; //初始化除数数据成员
}
void Compute::divideCompute() //除法类除法计算方法成员定义
{
try
{
if(m_value2== 0) //如果除数为0,则抛出相应异常
{
throwMyException(“divisor is 0!”);
}
else //否则计算两数相除,并打印结果
{
cout<<”m_value1/m_value2:”<<(m_value1/m_value2)<

ifndef EXCEPTION_H_

define EXCEPTION_H_

include

include

using namespace std;
//自定义异常类
class MyException
{
public:
MyException() //自定义异常类构造函数定义
{
m_context= “”; //初始化类异常信息数据成员为空
}
virtual~MyException(){} //异常类析构函数定义
MyException(const string & right) //异常类构造函数定义,通过传入字符串型参数初始化
{
m_context= right;
}
MyException(const char * right) //异常类构造函数定义,通过传入字符串指针参数初始化
{
m_context= right;
}
virtualstring what() const //异常类中虚拟what接口方法定义,获取异常信息
{
returnm_context;
}
protected:
string m_context; //异常类保护型数据成员,表示异常信息内容
};
//异常派生类,加入错误代码处理
class code_MyException : public MyException
{
public:
code_MyException(interror_code, string error_code_msg = “”, string context =”“)//异常派生类构造
{
m_errorCode= error_code; //错误代码初始化
m_errorCodeMsg= error_code_msg; //错误代码对应消息初始化
m_context= context; //对应异常信息初始化
}
stringwhat() const //派生类what接口重定义
{
chartmp[20]; //定义临时字符数组
sprintf(tmp,”%d”, m_errorCode); //格式化错误代码
returnstring(tmp) + “,” + m_errorCodeMsg + “,” + m_context; //返回连接的错误信息
}
intgetErrorCode() const //获取错误代码
{
returnm_errorCode;
}
stringgetErrorCodeMsg() const //获取错误代码对应信息
{
returnm_errorCodeMsg;
}
protected:
int m_errorCode; //错误代码
string m_errorCodeMsg; //错误信息
};

endif

上述实例中在原来异常类的基础之上派生了新的异常处理类,其中增加了错误代码以及错误信息的功能。利用C++继承机制,同时将其中的析构方法以及what接口定义为虚拟函数,有助于统一接口的实现。封装实现的异常处理类可以将其编译为库,作为系统中统一的组件供程序来使用。该实例的实际应用以及测试由初学者按照前面实例的方式来实践操作,从中领悟C++多态以及异常处理的好处。
14.4 标准库提供异常处理类
C++标准库同样对异常作出了封装实现。标准库中异常实现也采用类继承层次式的结构。库中针对异常处理提供了一个层次化的类结构。该类层次中顶层基类为exception,即针对其它不同情况下的异常处理类都派生自exception类。
针对异常处理,总共提供了八个标准异常处理。其中,四个针对语言级提供的抛出异常,分别为bad_alloc、bad_cast、bad_typeid以及bad_exception;另外四个为C++标准库抛出的异常,分别是out_of_range、invalid_argument、overflow_error以及ios_base::failure。下面将会针对这八类抛出异常情况作详细的讲述,分别说明每类异常表达的意义及基本用法。
1. bad_alloc
bad_alloc针对C++中动态存储分配new的操作提供的异常信号,主要针对分配内存空间时内存耗尽(分配不足)时抛出的异常。这种异常的抛出有利于开发者在实际应用中针对new操作分配内存时提供某种分配出错的处理方式。下面可以通过一个基本小代码片段来理解bad_alloc异常处理情况。
void newChar()
{
try
{
newchar[10000000000000]; //通过new开辟一个超大的内存空间
}catch(bad_alloc)
{
cout<<”memoryerror!”<

ifndef ERRORHANDLE_H_

define ERRORHANDLE_H_

include

include

include

using namespace std;
const int ERRORMSG_LEN = 300; //错误信息长度常量定义
class ErrorInfo //错误信息类
{
public:
ErrorInfo(){} //错误信息空构造函数定义
~ErrorInfo(){} //错误信息空析构函数定义
ErrorInfo(constErrorInfo& errorinfo); //错误信息类拷贝构造
public:
intm_errorNo; //错误信息类数据成员,表示错误代码
charm_message[ERRORMSG_LEN+1]; //错误信息类数据成员,表示错误信息
};

class ErrorMessages //错误消息容器类
{
public:
voidsetProgramInfo(const string& programInfoName); //错误消息容器类设置应用程序信息方法
stringgetProgramInfo(); //错误消息容器类获取应用程序信息方法
voidinsert(ErrorInfo &errInfo); //错误消息容器类插入错误信息方法
boolget(ErrorInfo& errInfo); //错误信息容器类获取错误信息方法
voidclean(); //清空错误消息队列方法
boolisEmpty(); //判断错误消息队列是否为空
voidinsert(const int errorCode, const string& errorMessage); //重载插入错误信息方法
voidinsert(const int errorCode, const char *errorMessage); //重载插入错误信息方法
private:
stringm_programInfoName; //错误消息类数据成员,表示应用程序名
dequem_errorInfoQueue; //错误消息类数据成员,表述错误信息队列
};

endif

//错误处理类源文件chapter1407_01.cpp

include “chapter1407_01.h”

ErrorInfo::ErrorInfo(const ErrorInfo&errorinfo) //错误信息类拷贝构造定义
{
m_errorNo= errorinfo.m_errorNo; //拷贝传入错误信息类对象的成员
strcpy(m_message,errorinfo.m_message);
}
void ErrorMessages::setProgramInfo(conststring& programInfoName) //设置应用程序信息方法定义
{
m_programInfoName= programInfoName; //根据传入的程序名设置
}
string ErrorMessages::getProgramInfo() //获取应用程序信息
{
returnm_programInfoName; //返回应用程序名称信息
}
void ErrorMessages::insert(ErrorInfo&errorinfo) //插入错误信息方法定义
{
m_errorInfoQueue.push_back(errorinfo); //将传入的错误信息类对象放入错误信息队列
}
void ErrorMessages::insert(const int errorCode,const string& errorMessage)//重载插入错误信息方法定义
{
ErrorInfoerrorinfo; //定义错误信息类对象实例
errorinfo.m_errorNo= errorCode; //将传入的错误代码赋值给该对象中数据成员
if(errorMessage.length() <= ERRORMSG_LEN) //如果传入的错误信息长度在规定之内
strcpy(errorinfo.m_message,errorMessage.c_str()); //则将错误信息拷贝到该对象对应数据成员中
else //否则扩充长度后再拷贝
{
strncpy(errorinfo.m_message,errorMessage.c_str(), ERRORMSG_LEN);
errorinfo.m_message[ERRORMSG_LEN]= 0;
}
insert(errorinfo); //最后插入到错误消息队列中
}
void ErrorMessages::insert(const int errorCode,const char *errorMessage)//插入错误信息重载方法定义
{
ErrorInfoerrorinfo; //定义错误信息类对象
errorinfo.m_errorNo= errorCode; //同上一方法定义
if(strlen(errorMessage) <= ERRORMSG_LEN)
strcpy(errorinfo.m_message,errorMessage);
else
{
strncpy(errorinfo.m_message,errorMessage, ERRORMSG_LEN);
errorinfo.m_message[ERRORMSG_LEN]= 0;
}
insert(errorinfo);
}
bool ErrorMessages::get(ErrorInfo& errorinfo) //获取错误信息队列中的信息
{
if(m_errorInfoQueue.empty()) //如果错误信息队列为空,则直接返回false
returnfalse;
errorinfo= m_errorInfoQueue.front(); //返回队列中头部的数据
m_errorInfoQueue.pop_front(); //删除队列中头部的数据
returntrue;
}
void ErrorMessages::clean() //清空错误信息队列
{
m_errorInfoQueue.clear(); //直接调用clear方法清除
}
bool ErrorMessages::isEmpty() //判断错误信息是否为空
{
returnm_errorInfoQueue.empty(); //直接调用empty方法判断
}
//错误处理类测试源文件chapter1407_02.cpp

include “chapter1407_01.h”

ErrorMessages errorMessages; //定义错误消息容器类对象
const int E_DIVISOR_ZERO = 200; //定义除数为0的错误代码常量
const string E_DIVISOR_ERROR = “divisor is0!”; //定义除数为0的错误信息常量
void divideCompute(int value1,int value2) //除法计算函数定义
{
if(value2== 0) //如果除数为0,则记录相应的错误信息
{
errorMessages.insert(E_DIVISOR_ZERO,E_DIVISOR_ERROR);//插入对应的错误代码与错误信息
}
else //否则计算除法并输出结果
{
cout<<”value1/value2:”<<(value1/value2)<

0 0