处理异常之书籍有:
C++ primer
C++ exception handling(C++异常处理)
thinking in c++
Exception c++》
More Exception c++》
wocow3»
查阅MSDN
这些API就算抛出异常也是WIN32异常,跟C++异常不太一样
jixingzhong»
这些函数,查MSDN就可以了
根据文档说明就明白
MFC异常处理浅析
2008-12-15 23:46
MFC中异常处理的语法和语义构建在标准C++异常处理语法和语义的基础之上,其解决方案为:
MFC异常处理 = MFC 异常处理类 + 宏
3.1宏
MFC定义了TRY、CATCH(及AND_CATCH、END_CATCH)和THROW(及THROW_LAST)等用于异常处理的宏,其本质上也是标准C++的try、catch和throw的进一步强化,由这些宏的定义可知:
#ifndef _AFX_OLD_EXCEPTIONS
#define TRY { AFX_EXCEPTION_LINK _afxExceptionLink; try {
#define CATCH(class, e) } catch (class* e) /
{ ASSERT(e->IsKindOf(RUNTIME_CLASS(class))); /
_afxExceptionLink.m_pException = e;
#define AND_CATCH(class, e) } catch (class* e) /
{ ASSERT(e->IsKindOf(RUNTIME_CLASS(class))); /
_afxExceptionLink.m_pException = e;
#define END_CATCH } }
#define THROW(e) throw e
#define THROW_LAST() (AfxThrowLastCleanup(), throw)
// Advanced macros for smaller code
#define CATCH_ALL(e) } catch (CException* e) /
{ { ASSERT(e->IsKindOf(RUNTIME_CLASS(CException))); /
_afxExceptionLink.m_pException = e;
#define AND_CATCH_ALL(e) } catch (CException* e) /
{ { ASSERT(e->IsKindOf(RUNTIME_CLASS(CException))); /
_afxExceptionLink.m_pException = e;
#define END_CATCH_ALL } } }
#define END_TRY } catch (CException* e) /
{ ASSERT(e->IsKindOf(RUNTIME_CLASS(CException))); /
_afxExceptionLink.m_pException = e; } }
这些宏在使用语法上,有如下特点:
(1)用TRY 块包含可能产生异常的代码;
(2)用CATCH块检测并处理异常。要注意的是,CATCH块捕获到的不是异常对象,而是指向异常对象的指针。此外,MFC靠动态类型来辨别异常对象;
(3)可以在一个TRY 块上捆绑多个异常处理捕获块,第一次捕获使用宏CATCH,以后的使用AND_CATCH,而END_CATCH则用来结束异常捕获队列;
(4)在异常处理程序内部,可以用THROW_LAST 再次抛出最近一次捕获的异常。
3.2 MFC 异常处理类
MFC较好地将异常封装到CException类及其派生类中,自成体系,下表给出了MFC 提供的预定义异常:
异常类 含义
CMemoryException 内存不足
CFileException 文件异常
CArchiveException 存档/序列化异常
CNotSupportedException 响应对不支持服务的请求
CResourceException Windows 资源分配异常
CDaoException 数据库异常(DAO 类)
CDBException 数据库异常(ODBC 类)
COleException OLE 异常
COleDispatchException 调度(自动化)异常
CUserException 用消息框警告用户然后引发一般 CException 的异常
标准C++的异常处理可以处理任意类型的异常,而3.1节的MFC 宏则只能处理CException 的派生类型,下面我们看一个CFileException的使用例子:
#include <iostream.h>
#include "afxwin.h"
int main()
{
TRY
{
CFile f( "d://1.txt", CFile::modeWrite );
}
CATCH( CFileException, e )
{
if( e->m_cause == CFileException::fileNotFound )
cout << "ERROR: File not found/n" << endl;
}
END_CATCH
}
在这个程序中,如果D盘根目录下不存在"1.TXT"这个文件,将抛出CFileException异常,而且错误原因成员变量m_cause被设置为fileNotFound,我们以CATCH( CFileException, e )就可以捕获到。错误原因被定义为CFileException中的枚举(enum),如下:
enum {
none,
generic,
fileNotFound,
badPath,
tooManyOpenFiles,
accessDenied,
invalidFile,
removeCurrentDir,
directoryFull,
badSeek,
hardIO,
sharingViolation,
lockViolation,
diskFull,
endOfFile
};
我们在使用MFC相关类时,MFC会自动抛出异常,当然我们也可以自行在程序中利用AfxThrowXXXException()抛出各种类型的异常,其中的XXX与前文的MFC异常类表对应。我们看AfxThrowFileException的例子:
#include <iostream.h>
#include "afxwin.h"
int main()
{
TRY
{
AfxThrowFileException(CFileException::fileNotFound);
}
CATCH( CFileException, e )
{
if( e->m_cause == CFileException::fileNotFound )
cout << "ERROR: File not found/n" << endl;
}
END_CATCH
}
在此程序中,我们在TRY块自行利用MFC提供的全局函数AfxThrowFileException抛出了CFileException异常,其后在CATCH块抓住了这个异常。
MFC建议不再使用TRY、CATCH和THROW宏,而是直接使用标准C++的方式。
C++中的异常处理浅析
2008-12-15 23:42
感谢C++语言的后期改造者们,他们在标准C++语言中专门集成了异常处理的相关语法(与之不同的是,所有的C 标准库异常体系都需要运行库的支持,它不是语言内核支持的)。当然,异常处理被加到程序设计语言中,也是程序语言发展和逐步完善的必然结果。我们看到,C++不是唯一集成异常处理的语言。
C++的异常处理结构为:
try
{
//可能引发异常的代码
}
catch(type_1 e)
{
// type_1类型异常处理
}
catch(type_2 e)
{
// type_2类型异常处理
}
catch (...)//会捕获所有未被捕获的异常,必须最后出现
{
}
而异常的抛出方式为使用throw(type e),try、catch和throw都是C++为处理异常而添加的关键字。看看这个例子:
#include <stdio.h>
//定义Point结构体(类)
typedef struct tagPoint
{
int x;
int y;
} Point;
//扔出int异常的函数
static void f(int n)
{
throw 1;
}
//扔出Point异常的函数
static void f(Point point)
{
Point p;
p.x = 0;
p.y = 0;
throw p;
}
int main()
{
Point point;
point.x = 0;
point.y = 0;
try
{
f(point); //抛出Point异常
//f(1); //抛出int异常
}
catch (int e)
{
printf("捕获到int异常:%d/n", e);
}
catch (Point e)
{
printf("捕获到Point异常:(%d,%d)/n", e.x, e.y);
}
return 0;
}
函数f定义了两个版本:f(int)和f(Point),分别抛出int和Point异常。当main函数的try{…}中调用f(point)时和f(1)时,分别输出:
捕获到Point异常:(0,0)
和
捕获到int异常:1
在C++中,throw抛出异常的特点有:
(1)可以抛出基本数据类型异常,如int和char等;
(2)可以抛出复杂数据类型异常,如结构体(在C++中结构体也是类)和类;
(3)C++的异常处理必须由调用者主动检查。一旦抛出异常,而程序不捕获的话,那么abort()函数就会被调用,弹出如图1所示的对话框,程序被终止;
(4)可以在函数头后加throw([type-ID-list])给出异常规格,声明其能抛出什么类型的异常。type-ID-list是一个可选项,其中包括了一个或多个类型的名字,它们之间以逗号分隔。如果函数没有异常规格指定,则可以抛出任意类型的异常。
2.2 标准异常
下面给出了C++提供的一些标准异常:
namespace std
{
//exception派生
class logic_error; //逻辑错误,在程序运行前可以检测出来
//logic_error派生
class domain_error; //违反了前置条件
class invalid_argument; //指出函数的一个无效参数
class length_error; //指出有一个超过类型size_t的最大可表现值长度的对象的企图
class out_of_range; //参数越界
class bad_cast; //在运行时类型识别中有一个无效的dynamic_cast表达式
class bad_typeid; //报告在表达试typeid(*p)中有一个空指针p
//exception派生
class runtime_error; //运行时错误,仅在程序运行中检测到
//runtime_error派生
class range_error; //违反后置条件
class overflow_error; //报告一个算术溢出
class bad_alloc; //存储分配错误
}
请注意观察上述类的层次结构,可以看出,标准异常都派生自一个公共的基类exception。基类包含必要的多态性函数提供异常描述,可以被重载。下面是exception类的原型:
class exception
{
public:
exception() throw();
exception(const exception& rhs) throw();
exception& operator=(const exception& rhs) throw();
virtual ~exception() throw();
virtual const char *what() const throw();
};
其中的一个重要函数为what(),它返回一个表示异常的字符串指针。下面我们从exception类派生一个自己的类:
#include <iostream>
#include <exception>
using namespace std;
class myexception:public exception
{
public:
myexception():exception("一个重载exception的例子")
{}
};
int main()
{
try
{
throw myexception();
}
catch (exception &r) //捕获异常
{
cout << "捕获到异常:" << r.what() << endl;
}
return 0;
}
程序运行,输出:
捕获到异常:一个重载exception的例子
一般的,我们直接以基类捕获异常,例如,本例中使用了
catch (exception &r)
然后根据基类的多态性进行处理,这是因为基类中的what函数是虚函数。
2.3异常处理函数
在标准C++中,还定义了数个异常处理的相关函数和类型(包含在头文件<exception>中):
namespace std
{
//EH类型
class bad_exception;
class exception;
typedef void (*terminate_handler)();
typedef void (*unexpected_handler)();
// 函数
terminate_handler set_terminate(terminate_handler) throw();
unexpected_handler set_unexpected(unexpected_handler) throw();
void terminate();
void unexpected();
bool uncaught_exception();
}
其中的terminate相关函数与未被捕获的异常有关,如果一种异常没有被指定catch模块,则将导致terminate()函数被调用,terminate()函数中会调用ahort()函数来终止程序。可以通过set_terminate(terminate_handler)函数为terminate()专门指定要调用的函数,例如:
#include <cstdio>
#include <exception>
using namespace std;
//定义Point结构体(类)
typedef struct tagPoint
{
int x;
int y;
} Point;
//扔出Point异常的函数
static void f()
{
Point p;
p.x = 0;
p.y = 0;
throw p;
}
//set_terminate将指定的函数
void terminateFunc()
{
printf("set_terminate指定的函数/n");
}
int main()
{
set_terminate(terminateFunc);
try
{
f(); //抛出Point异常
}
catch (int) //捕获int异常
{
printf("捕获到int异常");
}
//Point将不能被捕获到,引发terminateFunc函数被执行
return 0;
}
这个程序将在控制台上输出 "set_terminate指定的函数" 字符串,因为Point类型的异常没有被捕获到。当然,它也会弹出图1所示对话框(因为调用了abort()函数)。
上述给出的仅仅是一个set_terminate指定函数的例子。在实际工程中,往往使用set_terminate指定的函数进行一些清除性的工作,其后再调用exit(int)函数终止程序。这样,abort()函数就不会被调用了,也不会输出图1所示对话框。
关于标准C++的异常处理,还包含一些比较复杂的技巧和内容,我们可以查阅《more effective C++》的条款9~条款15