分享
 
 
 

C与C++中的异常处理3

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

1. 标准C++异常处理的基本语法和语义

这次,我来概述标准C++异常处理的基本语法和语义。顺便,我会将它和前两次提到的技术进行比较。(在本文及以后,我将标准C++异常处理简称为EH,将微软的方法称为SEH。)

1.1 基本语法和语义

EH引入了3个新的C++语言关键字:

l catch

l throw

l try

异常通过如下语句触发

throw [expression]

函数通过“异常规格申明”定义它将抛出什么异常:

throw([type-ID-list])

可选项type-ID-list包含一个或多个类型的名字,以逗号分隔。这些异常靠try块中的异常处理函数进行捕获。

try compound-statement handler-sequence

处理函数队列包含一个或多个处理函数,形式如下:

catch ( exception-declaration ) compound-statement

处理函数的“异常申明”指明了这个函数将捕获什么类型的异常。

和SEH一样,跟在try和catch后面的语句必须刮在{}内,而整个try块组成一条完整的大语句。

例子:

void f() throw(int, some_class_type)

{

int i;

// ... generate an 'int' exception

throw i;

// ...

}

int main()

{

try

{

f();

}

catch(int e)

{

// ... handle 'int' exception ...

}

catch(some_class_type e)

{

// ... handle 'some_class_type' exception ...

}

// ... possibly other handlers ...

return 0;

}

异常规格申明是EH特有的,SEH和MFC都没有类似的东西。一个空的异常规格申明表明函数不抛出任何异常:

void f() throw()

{

// ... function throws no exceptions ...

}

如果函数没有异常规格申明,它可以抛出任何类型的异常:

void f()

{

// ... function can throw anything or nothing ...

}

当函数抛异常时,关键字throw通常后面带一个被抛出的对象:

throw i;

然而,throw也可以不带对象:

catch(int e)

{

// ... handle 'int' exception ...

throw;

}

它的效果是再次抛出当前正被捕获的对象(int e)。因为空throw的作用是再次抛出已存在的异常对象,所以它必须位于catch语句块中。MFC也有再次抛出异常的功能,SEH则没有,它没有将异常对象交给过处理函数,所以没什么可再次抛出的。

就象函数原型中的参数申明一样,异常申明也可以是无名的:

catch(char *)

{

// ... handle 'char *' exception ...

}

当这个处理函数捕获一个char *型的异常对象时,它不能操作这个对象,因为这个对象没有名字。

异常申明还可以是这样的特殊形式:

catch(...)

{

// ... handle any type of exception ...

}

就象不定参数中的“...”一样,异常申明中的“...”可以匹配任何异常的类型。

1.2 标准异常对象的类型

标准库函数可能报告错误。在C标准库中的报错方式在前面说过了。在C++标准库中,有些函数抛出特定的异常,而另外一些根本不抛任何异常。

因为C++标准中没有明确规定,所以C++的库函数可以抛出任何对象或不抛。但C++标准推荐运行库的实现通过抛出定义在<stdexecpt>中的异常类型或其派生类型来报告错误:

namespace std

{

class logic_error; // : public exception

class domain_error; // : public logic_error

class invalid_argument; // : public logic_error

class length_error; // : public logic_error

class out_of_range; // : public logic_error

class runtime_error; // : public exception

class range_error; // : public runtime_error

class overflow_error; // : public runtime_error

class underflow_error; // : public runtime_error

}

这些(异常)类只对C++标准库有约束力。在你自己的代码中,你可以抛出(和捕获)任何你所象要的类型。

1.3 标准中的其它申明

标准库头文件<exception>申明了几个EH类型和函数

namespace std

{

//

// types

//

class bad_exception;

class exception;

typedef void (*terminate_handler)();

typedef void (*unexpected_handler)();

//

// functions

//

terminate_handler set_terminate(terminate_handler) throw();

unexpected_handler set_unexpected(unexpected_handler) throw();

void terminate();

void unexpected();

bool uncaught_exception();

}

提要:

l exception是所有标准库抛出的异常的基类。

l uncaught_exception()函数在有异常被抛出却没有被捕获时返回true,其它情况返回false。它类似于SEH的函数AbnormalTermination()。

l terminate()是EH的应急处理。它在异常处理体系陷入了不可恢复状态时被调用,经常是因为试图重入(在前一个异常正处理过程中又抛了一个异常)。

l unexpected()在函数抛出一个它没有在“异常规格申明”中申明的异常时被调用。这个预料外的异常可能在退栈过程中被替换为一个bad_excetion对象。

l 运行库提供了缺省terminate_handler()和unexpected_handler() 函数处理对应的情况。你可以通过set_terminate()和set_unexpected()函数替换库的默认版本。

1.4 异常生命期

EH运行于异常生命期的五个阶段:

l 程序或运行库遇到一个错误状况(阶段1)并且抛出一个异常(阶段2)。

l 程序的运行停止于异常点,开始搜索异常处理函数。搜索沿调用栈向上搜索(很象SEH终止异常时的行为)。

l 搜索结束于找到了一个异常申明与异常对象的静态类型相匹配(阶段3)。于是进入相应的异常处理函数。

l 异常处理函数结束后,跳到此异常处理函数所在的try块下面最近的一条语句开始执行(阶段5)。这个行为意味着C++标准中异常总是终止。

这些步骤演示于这个简单的例子中:

#include <stdio.h>

static void f(int n)

{

if (n != 0) // Stage 1

throw 123; // Stage 2

}

extern int main()

{

try

{

f(1);

printf("resuming, should never appear\n");

}

catch(int) // Stage 3

{

// Stage 4

printf("caught 'int' exception\n");

}

catch(char *) // Stage 3

{

// Stage 4

printf("caught 'char *' exception\n");

}

catch(...) // Stage 3

{

// Stage 4

printf("caught typeless exception\n");

}

// Stage 5

printf("terminating, after 'try' block\n");

return 0;

}

/*

When run yields

caught 'int' exception

terminating, after 'try' block

*/

1.5 基本原理

C标准库的异常体系处理C++语言时有如下难题:

l 析构函数被忽略。既然C标准库异常体系是为C语言设计的,它们不知道C++的析构函数。尤其,abort()、exit()和longjmp()在退栈或程序终止时不调用局部对象的析构函数。

l 繁琐的。查询全局对象或函数返回值导致了代码混乱-你必须在所有可能发生异常的地方进行明确的异常情况检测,即使是异常情况可能实际上从不发生。因为这种方法是如此繁琐,程序员们可能会故意“忘了”检测异常情况。

l 无弹性的。Longjmp()“抛出”的只能是简单的int型。errno和signal()/raise()只使用了很小的一个值域集合,分辨率很低。Abort()和exit()总是终止程序。Assert()只工作在debug版本中。

l 非固有的。所有的C标准库异常体系都需要运行库的支持,它不是语言内核支持的。

微软特有的异常处理体系也不是没有限制的:

l SEH异常处理函数不是直接捕获一个异常对象,而是通过查询一个(概念性的)类似errno的全局值来判断什么异常发生了。

l SEH异常处理函数不能组合,给定try块的唯有的一个处理函数必须在运行期识别和处理所有的异常事件。

l MFC异常处理函数只能捕获CException及派生类型的指针。

l 通过包含定义了MFC异常处理函数的宏的头文件,程序包含了数百个无关的宏和申明。

l MFC和SEH都是专属于与Microsoft兼容的开发环境和Windows运行平台的。

标准C++异常处理避免了这些短处:

l 析构安全。在抛异常而进行退栈时,局部对象的析构函数被按正确的顺序调用。

l 不引人注目的。异常的捕获是暗地里的和自动的。程序员无需因错误检测而搞乱设计。

l 精确的。因为几乎任何对象都可以被抛出和捕获,程序员可以控制异常的内容和含义。

l 可伸缩的。每个函数可以有多个try块。每个try块可以有单个或一组处理函数。每个处理函数可以捕获单个类型,一组类型或所有类型的异常。

l 可预测的。函数可以指定它们将抛的异常类型,异常处理函数可以指定它们捕获什么类型的异常。如果程序违反了其申明,标准库将按可预测的、用户定义的方式运行。

l 固有的。EH是C++语言的一部分。你可以定义、throw和catch异常而不需要包含任何库。

l 标准的。EH在所有的标准C++的实现中都可用。

基于更完备的想法,C++标准委员会考虑过两个EH的设计,在D&E的16章。(For a more complete rationale, including alternative EH designs considered by the C++ Standard's committee, check out Chapter 16 of the D&E.)

1.6 小结

下次,我将更深入挖掘EH的语言核心特性和EH的标准库支持。我也将展示Microsoft Visual C++实现EH的内幕。我将开始标志出EH的那些Visual C++只部分支持或完全不支持的特性,并且寻找绕过这些限制的方法。

在我相信设计EH的基本原理是健全的的同时,我也认为EH无意中包含了一些严重的后果。不用责备C++标准的制订者的短视,我理解设计和实现有效的异常处理是多么的难。当我们遭遇到这些无意中的后果时,我将展示它们对你代码的微妙影响,并且推荐一些技巧来减轻其影响。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有