010异常处理Word格式.docx
《010异常处理Word格式.docx》由会员分享,可在线阅读,更多相关《010异常处理Word格式.docx(32页珍藏版)》请在冰豆网上搜索。
{
if((iRet=CreateTable()==0))
{
//...
return0;
}
else
//错误处理
return-1;
}
else
//错误处理
return-1;
}
else
return?
?
//或者
if((iRet=CreateDb())<
0)
//return?
if((iRet=CreateUser())<
if((iRet=CreateTable()<
0))
return0;
代码变得复杂而难以维护,而如果使用异常处理,可简化为如下形式
voidCallFunc()
try
InitDb();
catch(?
)
//异常处理
voidInitDb()
CreateDb();
//在CreateDb()内部如果执行失败,抛出异常
CreateUser();
//在CreateUser()内部如果执行失败,抛出异常
CreateTable();
//在CreateTable()函数内部如果执行失败,抛出异常
2.C++标准异常处理
2.1.C++异常处理
C++的异常处理分为两部分,第一部分是检查程序处理情况,如果处理结果非期望的结果,则生成一个异常,并将异常抛出,抛出后,由异常的接收者处理这个异常,异常抛出的语法形式为:
throw异常对象
throw是C++关键字,表示要抛出异常。
异常对象表示异常信息,它既可以是普通数据类型的实例,也可以是类类型的对象实例。
异常处理的第二部分捕捉被抛出的异常,并对异常进行处理,其形式为:
//程序执行语句,可能抛出异常。
}
catch(异常类型[,参数])
//处理异常
其中try是关键字,其后的语句块叫try块,其中的一些语句直接(比如throw表达式)或者间接(比如对包含throw表达式的函数的调用)地抛出异常。
抛出的异常只有在try语句块中才能被catch语句捕获。
紧接着try块的是catch语句,用来捕获异常,catch之后的括号中含有数据类型参数,参数类型说明了希望捕获的异常的具体类型,catch中的参数类型之后的参数是可选的。
如果有参数,则异常被捕获时,抛出的异常对象会初始化参数。
catch中包含参数使得在被捕获的对象信息可以在异常处理程序中被使用。
catch后的语句块就是对应于被捕获的异常的处理程序。
#include"
stdafx.h"
#include<
iostream>
usingnamespacestd;
classCMyError
public:
CMyError()
cout<
<
"
CMyError()"
endl;
CMyError(constCMyError&
obj)
CMyError(constCMyError&
obj)"
~CMyError()
~CMyError()"
};
classCTest
public:
intFunc(inti)
if(i<
10)
throwCMyError();
//强制类型转换,抛出类类型实例
20)
throw-1;
//抛出基本类型数据的实例
returni;
intmain(intargc,char*argv[])
CTesttest;
intiIn;
cin>
>
iIn;
intx=test.Func(iIn);
Attheendoftryblock"
//也可以是
//catch(CMyError)
//catch(CMyError&
e)
//如果抛出来的是堆中分配的对象的指针
//此处也可以接收指针。
catch(CMyErrore)
catchCErrorobject"
intb=2;
//也可以接收标准数据类型的实例
catch(inti)
catchintvariable:
i<
如果throw表达式或者抛出异常的子函数没在当前函数的try语句块中,或者虽然包含在try语句块中,但是catch捕捉的类型与实际抛出的类型不匹配,那系统将把异常抛给上一层次的函数,直到遇到一个能够处理改异常的函数。
voidFunc1()
CTestt;
t.Func(3);
voidFunc2()
Func1();
voidFunc3()
Func2();
catch(...)
//...
如果直到最外层的main函数都没能捕捉到异常,则系统会自动调用函数:
voidterminate();
该函数在eh.h中定义,缺省情况下,terminate()将调用abort()来终止程序,abort()终止程序的同时输出缺省的异常提示信息。
//!
!
有问题!
程序员也可以通过函数set_terminate()改变最终的默认异常接收函数terminate,set_terminate()的原型为:
//typedefvoid(*pfv)();
//pfvset_terminate(pfv);
//但是不管你设置的异常接受函数内部怎么处理,函数执行完毕后,程序结束执行。
2.2.多个异常的组织
2.2.1.多个异常
●一个函数可以抛出多个异常,可以在try块后放置多个catch块来捕获多个异常,如上例;
●异常也可以嵌套,里层抛出的异常一层层地往外匹配catch块,直到匹配成功或者跳出main()交系统处理。
intFunc()
try
throwchar
(1);
catch(intie)
cout<
level1catch"
catch(charce)
level2catch"
里层的异常将被外层的catch捕获。
●异常被捕获后,仍可将异常再次抛出以期待被外层的catch捕获。
再次抛出异常用关键字throw即可,不必加上再次抛出的异常名,实际上,它隐含地认为抛出的是当前捕获的异常对象。
inti=9;
throwi;
catch(intie)
Func2()catch"
throw;
voidFunc()
Func()catch"
Func();
2.2.2.用枚举组织异常
一个函数往往会产生各种异常,这就要求对各种异常进行组织和管理。
方法之一是用枚举来组织异常。
enumENUM_ERROR{StackOverflow,NullPointer,ZeroDevide};
voidFunc(inti)
if(i%3==0)
throwStackOverflow;
if(i%4==0)
throwNullPointer;
if(i%5==0)
throwZeroDevide;
throw0;
//注意,不同于throwENUM_ERROR(0);
inti;
i;
Func(i);
catch(ENUM_ERRORe)
switch(e)
caseStackOverflow:
StackOverflow"
break;
caseNullPointer:
NullPointer"
caseZeroDevide:
ZeroDevide"
Unknownexception!
2.2.3.用虚函数组织异常
利用虚函数组织异常可以使得在增加新的异常时不必修改源程序,同时又能按具体的异常对象自动选择合适的异常处理程序。
只要把异常类中与异常处理有关的函数声明为虚函数,并把catch()中的类型参数设定为基类的引用或者指针就行了。
这样,在异常处理中只要统一按照对基类异常的处理就行了。
classCErrorBase
virtualvoidPrintError()
CErrorBase"
classCErrorOverflow:
publicCErrorBase
CErrorOverflow"
classCErrorNullPointer:
CErrorNullPointer"
classCErrorZeroDevide:
CErrorZeroDevide"
throwCErrorOverflow();
throwCErrorNullPointer();
throwCErrorZeroDevide();
catch(CErrorBase&
e.PrintError();
这样使得对异常的处理变得简单而统一,事实上,MFC的异常处理就是以此为基础的。
2.3.异常接口说明
一个函数往往要抛出异常对象,函数的使用者应当了解函数所抛出的异常,从而设置catch语句捕获异常对象,并对捕获的异常对象进行处理,但是,除非看到函数的源代码,否则函数的使用者无法从函数的原型声明中知道函数可能抛出的异常。
C++为此提供了异常的接口说明,它在函数说明中就列出了函数可能抛出的异常,因为不必了解函数代码就可以知道函数与哪些异常有关。
异常接口说明是函数声明的一部分,它紧跟在普通的函数声明之后。
异常接口说明的一般形式为:
返回类型函数名(参数列表)throw(异常类型1,异常类型2,,,);
throw后扩后内的内容是此函数可能抛出的所有异常的集合。
各类型间用逗号隔开。
例如:
voidfunc(inti)throw(char,int);
说明函数func只可能抛出char类型和int类新的异常对象,而不会再抛出其他异常。
如果一个函数声明中没有异常说明列表,那么隐含地表示函数可以抛出任何类型的异常。
intFunc(inti);
表示Func函数可能会抛出各种类型的异常。
如果规定函数不会抛出任何异常,则应该设置函数声明的异常接口为空,例如:
intFunc(inti)throw();
说明Func函数不会抛出任何异常。
3.MFC异常处理
MFC异常的语法和语义是构建在标准C++异常的语法和语义的基础上的,是用宏的方式对标准C++的异常进行包装。
MFC异常类体系是以虚函数方式组织的。
CException是所有MFC异常类的基类,
所有名字为CXXXException形式的类都是从抽象类CException派生的。
下表显示由MFC提供的预定义异常。
异常类
含义
CMemoryException
内存不足
CFileException
文件异常
CArchiveException
存档/序列化异常
CNotSupportedException
响应对不支持服务的请求
CResourceExceptionWindows
资源分配异常
CDaoException
数据库异常(DAO类)
CDBException
数据库异常(ODBC类)
COleException
OLE异常
COleDispatchException
调度(自动化)异常
CUserException
用消息框警告用户然后引发一般CException的异常
MFC则定义了一组宏:
TRY
CATCH,AND_CATCH,和END_CATCH
THROW和THROW_LAST
这些宏非常象C++的异常关键字try、catch和throw。
对于每个MFC异常类CXXXException,都有一个全局的辅助函数AfxThrowXXXException(),它构造、初始化和抛出这个类的对象。
你可以用这些辅助函数处理预定义的异常类型,用THROW处理自定义的对象(当然,它们必须是从CException派生的)。
基本的设计原则是:
用TRY块包含可能产生异常的代码。
用CATCH检测并处理异常。
异常处理函数并不是真的捕获对象,它们其实是捕获了指向异常对象的指针。
MFC靠动态类型来辨别异常对象。
可以在一个TRY块上捆绑多个异常处理函数,每个捕获一个C++静态类型的不同的对象。
第一个处理函数使用宏CATCH,以后的使用AND_CATCH,用END_CATCH结束处理函数队列。
MFC自己可能触发异常,你也可以显式触发异常(通过THROW或MFC辅助函数)。
在异常处理函数内部,可以用THROW_LAST再次抛出最近一次捕获的异常。
例,使用MFC内设异常类:
TRY
printf("
raisingmemoryexception\n"
);
AfxThrowMemoryException();
thislineshouldneverappear\n"
CATCH(CException,pe)//!
!
注意,抛出的是对象的指针
caughtgenericexception;
rethrowing\n"
THROW_LAST();
//重新抛出必须用THROW_LAST();
而不是THROW()
END_CATCH
printf("
CATCH(CFileException,pe)
caughtfileexception\n"
AND_CATCH(CMemoryException,pe)
caughtmemoryexception\n"
AND_CATCH(CException,pe)//捕获剩下的MFC异常类对象
caughtgenericexception\n"
pe->
ReportError();
int_tmain(intargc,TCHAR*argv[],TCHAR*envp[])
AfxWinInit(:
:
GetModuleHandle(NULL),NULL,:
GetCommandLine(),0);
Func3();
使用自定义的MFC异常派生类:
classCMyException:
publicCException
virtualBOOLGetErrorMessage(LPTSTRlpszError,UINTnMaxError,PUINTpnHelpContext)
ASSERT(lpszError!
=NULL&
&
AfxIsValidString(lpszError,nMaxError));
charszError[]="
我的错误处理信息!
;
strncpy(lpszError,szError,nMaxError-1);
lpszError[nMaxError-1]=0;
returnTRUE;
THROW(newCMyException);
Func();
CATCH(CException,pe)
4.Win32结构化异常处理(SEH)
Windows95、Windows98和Windows2000(即以前的WindowsNT)支持一种称为结构化异常处理的可靠的异常处理方法,此方法涉及与操作系统的协作,并且在编程语言中具有直接支持。
“SEH异常”是意外的或是使进程不能正常进行的事件。
硬件和软件都可以检测出异常。
硬件异常包括被零除和数值类型溢出等。
软件异常包括通过调用RaiseException函数检测到并发出信号通知系统的情况,以及由Windows检测到的特殊情况。
可以使用结构化异常处理编写更可靠的代码。
可以确保资源(如内存块和文件)在发生意外终止事件时正常关闭。
还可以利用简洁的、不依靠goto语句或详细测试返回代码的结构化代码来处理具体问题(如内存不足)。
注意:
结构化异常处理文章描述C编程语言的结构化异常处理。
虽然结构化异常处理也可用于C++,但对于C++程序应使用C++异常处理。
SEH是系统一级的异常处理,当建立标准C++异常处理时,编译器最终将它翻译成SEH异常处理。
SEH实际包含两个主要功能,结束处理和异常处理。
分别通过__try{}__finally{}结构和__try{}__except(){}结构实现。
4.1.__try{}__finally{}结构
此结构能够确保__try{}块内的代码执行完毕后,进入__finally{}块中执行一些清理工作。
FILE*f=NULL;
__try{
f=fopen("
abc.txt"
"
wb"
//执行一些文件处理工作
if(fwrite("
aaa"
1,3