MinGW异常机制实现的探究

终于放假了,而我的csdn博客也是长期没有整理。最近我常常考虑异常的问题,所以今天的时候我探究了一下c++究竟是怎么实现异常的。写完这篇之后,我感觉我对异常的了解更深了。

C++Exception的中文翻译“异常”决定了它的主要用途必然是用于错误处理;确切的说,是为处理当前模块无法处理的情况而把处理权交给上一层模块。不过,当然不能被这个词语所局限。抛出Exception的不一定是异常的状况。有的时候我们会遇到这种情况:一个函数可能需要根据不同情况返回多种不同类型的值、或者一个函数可能需要或可能不需要返回值。利用Exception可以优雅地解决这些问题。标准情况只有一个返回方法(return关键字),而Exception可以提供另一种更加灵活的返回方法。

之所以Exception适用于错误处理,是因为错误本身是不同于函数本身返回值类型的返回值。

/*******************************************

<Author>Bowen YU</Author>

<Describe>

Bank System: My Program for CPP Examination

Demonstrating an uncommon use of exception

</Describe>

<Todo></Todo>

*******************************************/

#include "Account.h"

#include "Ui.h"

#include <iostream>

using namespace std;

 

int main(void)

{

    try{

        for(;;)

        {

            display_Main();

            dologic_Main();

        }

    }catch(ExceptionQuit)

    {

    }

    return 0;

}

以上代码是我在C++考试写的一个命令行交互程序,本来需要一个标志exit来标记是否退出,并且每次for循环的时候都需要判断是否exit。我写的这段代码则避免了繁琐,写得很简洁。

/*******************************************

<Author>Bowen YU</Author>

<Describe>

A Simple Program Demonstrating The Use of Exception

</Describe>

<Todo></Todo>

*******************************************/

 

class ExceptionSimple { };

 

int f(bool p)

{

    if(p)

    {

        throwExceptionSimple();

    }

    else

    {

        return0;

    }

}

 

int main(void)

{

    try

    {

        f(false);

        f(true);

    }

    catch(ExceptionSimplees)

    {

        __asm__("nop;nop; nop;");

    }

   

    return 0;

}

其中main的汇编代码,注意到LEHB0LEHE0包含了try块里面的代码。

LEHB0:

call    __Z1fb  //f(0);

    movl    $1, (%esp)

    call    __Z1fb  //f(1);

LEHE0:

L7:

    movl    $0, %eax //return 0;

    leave

ret

f的汇编代码,cxa_allocate_exception(1)给抛出的对象分配内存,而cxa_throw(0,&_ZTI15ExceptionSimple,%eax)抛出异常。

    pushl   %ebp

    movl        %esp,%ebp

    subl        $40,%esp

    movl        8(%ebp),%eax

    movb        %al,-12(%ebp)

    cmpb        $0,-12(%ebp)

    je      L2

    movl        $1,(%esp)

    call        cxa_allocate_exception

    movl        $0, 8(%esp)

    movl        $ZTI15ExceptionSimple,4(%esp)

    movl        %eax,(%esp)

    call        cxa_throw

L2:

    movl        $0,%eax

    leave

    ret

异常处理代码

L8:

cmpl        $1,%edx

    je      L6

    movl        %eax,(%esp)

    call        Unwind_Resume

L6:

    movl        %eax,(%esp)

    call        cxa_begin_catch

    nop; nop;nop;

    call        cxa_end_catch

    jmp     L7

L7:

    movl        $0,%eax  //return 0; of main()

    leave

    ret

Exception Table

.section    .gcc_except_table,"w"

.align 4

    .uleb128LEHB0-LFB1

    .uleb128LEHE0-LEHB0

    .uleb128L8-LFB1

_ ZTS15ExceptionSimple记录了异常名,是个字符串。

_ZTI15ExceptionSimple是个结构体,分别包含一个int和一个char*。其中int型的__ZTVN10__cxxabiv117__class_type_infoE+8应该可以推测类的信息。

__ZTI15ExceptionSimple:

    .long   __ZTVN10__cxxabiv117__class_type_infoE+8

    .long   __ZTS15ExceptionSimple

__ZTS15ExceptionSimple:

    .ascii"15ExceptionSimple\0"

由上面所给出的材料可以得出的一些结论:

1.        MinGW实现异常机制的时候引入了“异常表”(Exception Table),抛出异常之后会在异常表内寻找异常处理程序的位置。并且这里被抛出的对象在运行期不仅仅具有值,还有表示其类型的唯一标识符和显示名(见ZTS15ExceptionSimple),与通常时候类型信息仅仅在编译期存在的观念不一样(与此类比的是RTTI(运行时类型))。因此决定了C++throw可以抛出不同类型的对象并且可以根据其类型选择异常处理程序。

2.        异常一个重量级的特性,比一般的return要付出更多的性能代价。不要在性能敏感的地方使用异常,也不要把经常发生的情况交给异常处理程序。

 

俞博文 2013-1-21

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值