C++&windows异常处理学习笔记

一、c++

c++的异常处理机制包括:

抛出异常

捕获异常

处理异常

C++使用throw抛出异常,try…catch捕获和处理异常。

例如:

#include<stdio.h>

#include<string.h>

 

char* _strcpy(char *a, const char *s)
{
try
{
char *temp;
printf("before throw ");
if (NULL == a || NULL == s)
throw string("Invalid argument(s)");//抛出异常。这里还有疑问:究竟谁可以抛出异常?程序自己肯定可以,
                                    //但有的例子中并没有throw语句,难不成是系统抛出的?
temp = a;
printf("after throw");
return temp;
}
catch(string &e)//捕获并处理异常,格式为catch(异常类型名 异常对象名)
{
printf("%s\n", e.c_str());
}
catch(int i)
{
printf("%d\n", i); 
 }

}  

int main(int argc, char* argv[])

{

char a[32];

_strcpy(a,NULL);

return0;

}

在执行完throw语句后,系统将不执行throw后面的语句,而是直接跳到相应的catch块执行相应的异常处理。执行完catch块后直接转到try - catch后面的语句执行。如上例,系统将输出“before throw Invalid argument(s)”。

try - catch语句可以嵌套。

c++中的异常规范提供了在函数生命中描述该函数可能抛出异常的方法,异常规范跟随在函数参数列表之后,它使用关键字throw来指定,举例如下:

int f(int a,int b);//f可能抛出任何异常

int g(int a,int b) throw(char,string);//g可能抛出整型、字符串型异常

int h(int a,int b) throw();//h不会抛出异常

二、windows

windows的异常处理机制,称为SEH( structured exception handling ), SEH的异常处理模型包括__try-__except语句和__try-__finally语句。

__try-__except异常处理机制和C++的很相像,只是关键字是__except而不是catch。另外catch关键字后面好像接受一个函数参数一样,可以是各种类型的异常数据对象,但是__except关键字则不同,它后面跟的是一个表达式(可以是各种类型的表达式)。

例如:

void main()
{
puts("hello");
// 定义受监控的代码模块
__try
{
puts("in try");
}
//定义异常处理模块
__except(EXCEPTION_EXECUTE_HANDLER)
{
puts("in except");
}
puts("world");
}

受监控的代码模块被执行(也即__try定义的模块代码); 
如果上面的代码执行过程中,没有出现异常的话,那么控制流将转入到__except子句之后的代码模块中; 
否则,如果出现异常的话,那么控制流将进入到__except后面的表达式中,也即首先计算这个表达式的值,之后再根据这个值,来决定做出相应的处理。

EXCEPTION_CONTINUE_EXECUTION (–1) 异常被忽略,控制流将在异常出现的点之后,继续恢复运行。 
EXCEPTION_CONTINUE_SEARCH (0) 异常不被识别,也即当前的这个__except模块不是这个异常错误所对应的正确的异常处理模块。系统将继续到上一层的__try-__except域中继续查找一个恰当的__except模块。 
EXCEPTION_EXECUTE_HANDLER (1) 异常已经被识别,也即当前的这个异常错误,系统已经找到了并能够确认,这个__except模块就是正确的异常处理模块。控制流将进入到__except模块中。

为了在__except模块中获得异常错误的相关信息,Windows提供了两个API函数

LPEXCEPTION_POINTERS GetExceptionInformation(VOID);
DWORD GetExceptionCode(VOID);

SEH异常处理模型中,对异常划分为两大类,第一种就是上面一些例程中所见到的,这类异常是系统异常,也被称为硬件异常;还有一类,就是程序中自己抛出异常,被称为软件异常(这和C++的throw关键字作用相似)。抛出软件异常需要调用Windows提供的API函数,它的声明如下:

VOID RaiseException(
DWORD dwExceptionCode, // exception code
DWORD dwExceptionFlags, // continuable exception flag
DWORD nNumberOfArguments, // number of arguments in array
CONST DWORD *lpArguments // address of array of arguments

);

__try-__finally

__try-__finally语句的语法与__try-__except很类似,稍有不同的是,__finally后面没有一个表达式,这是因为__try-__finally语句的作用不是用于异常处理,所以它不需要一个表达式来判断当前异常错误的种类。另外,与__try-__except语句类似,__try-__finally也可以是多层嵌套的,并且一个函数内可以有多个try-finally语句,不管它是嵌套的,或是平行的。当然,__try-__finally多层嵌套也可以是跨函数的。

最关键的一点: “不管在何种情况下,在离开当前的作用域时,finally块区域内的代码都将会被执行到”

例如:

void tmain()
{
puts("hello");
__try
{
puts("__try块中"); 
// 注意,下面return语句直接让函数返回了
return;
}
__finally
{
puts("__finally块中");
} 
puts("world");

上面的程序运行结果如下: 
hello 
__try块中 
__finally块中 
Press any key to continue


__finally块被执行的流程时,无外乎三种情况。

第一种就是顺序执行到__finally块区域内的代码,这种情况很简单,容易理解;

第二种就是goto语句或return语句引发的程序控制流离开当前__try块作用域时,系统自动完成对__finally块代码的调用;

第三种就是由于在__try块中出现异常时,导致程序控制流离开当前__try块作用域,这种情况下也是由系统自动完成对__finally块的调用。

无论是第 2种,还是第3种情况,毫无疑问,它们都会引起很大的系统开销,编译器在编译此类程序代码时,它会为这两种情况准备很多的额外代码。

一般第2种情况,被称为“局部展开(LocalUnwinding)”;第3种情况,被称为“全局展开(GlobalUnwinding)”。。

第3种情况,也即由于出现异常而导致的“全局展开”,对于程序员而言,这也许是无法避免的,因为你在利用异常处理机制提高程序可靠健壮性的同时,不可避免的会引起性能上其它的一些开销。呵呵!这世界其实也算瞒公平的,有得必有失。

有用的博文:

www.doc88.com/p-90394592801.html

http://www.cnblogs.com/wenziqi/archive/2010/08/26/1809074.html

http://www.cppblog.com/yehao/articles/165099.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值