鱼和熊掌兼得——在VC++中混用C++异常和结构化异常(转载)

结构化异常处理看过一些,不过都忘了。某些类型的异常看来还需要结构化异常来处理,还是要根据场景来使用吧。等温习使用了之后,在详细介绍其中的妙处。

------------------------ZT from: http://gamebabyrocksun.blog.163.com/blog/static/57153463200893113221505/

鱼和熊掌兼得——在VC++中混用C++异常和结构化异常 2008-10-03 11:32


       很长时间没有更新自己的博客了,今天算是有一点闲暇时间吧,写点东西,献给那些经常关注我博客的网友。今天的话题还是关于异常处理的。

       在我学习C++ 以及VC++ 甚至windows编程的很长一段时间里,对于异常是没什么概念的,也不经常使用,甚至当我看到java的程序员几乎把所有的代码都用异常包裹起来的时候,我都觉得他们有点变态。

       在一个偶然的机会,我也不知道为什么我居然成了一名网游服务端的主程(其实我梦想的是写超炫的客户端),写服务程序,那要求就是高稳定,高性能,高度灵活,高扩展性,对于性能我是不怎么担心的,甚至扩展性我也不担心,灵活性就用lua搞定吧,可是稳定性对我却是一个不小的挑战。人非圣贤,孰能无过?因此代码中总是隐藏着很多莫名其妙的问题,这可是服务程序啊,任何的问题都可能导致严重的后果。你可以想象一下几万人甚至几十万人因为你糟糕的服务程序,而同时砸鼠标和键盘的样子,我只能默默祈祷他们不要认识我,否则我都不敢上街了,说到这其实可以看出当个程序员有多麽的不容易!

       在这些问题面前我能做的就是把异常处理这招用上了,开始我使用了的C++的异常处理,可是我沮丧的发现有些异常居然没法截获,程序依然固执的退出了事,郁闷,超级郁闷,于是我琢磨着放弃这个该死的C++异常处理,换用Windows系统的结构化异常处理,可是更糟糕的事情发生了,结构化异常的语法太怪异了,居然没有throw,而要使用一个函数RaiseException,同时C++的异常有无法截获了,哎,真是鱼和熊掌啊!怎么办?本着试试的态度,我在代码中既写了C++的异常处理,也用了一些结构化异常处理的代码,结果编译时,编译器告诉我不能在C++中使用结构化异常,要混用就要打开/EHsc开关,我在项目属性的C/C++选项下的代码生成选项中找到了它,选项名称是启用C++异常,下拉框中有个/EHsc的选项,于是我使用了它,开始编译,哦,非常棒!代码都编过了。我感觉非常的棒,可是等等,好像问题还是没有解决,两种异常处理在代码中还是水火不容的,怎么办?这下不知道怎么办了。

通常VC++的程序员在不知道怎么办的时候,最好的方法就是(注意不是上网)——而是打开MSDN,我在里面找到/EH选项的帮助,都是些没什么用的信息,老习惯我点了几个里面的连接,其中有一个名字叫做_set_se_translator的函数让我眼睛一亮,凭着多年看MSDN的经验,我相信这后面已经隐藏着一个惊天的秘密,微软的帮助就是这样,在一堆没用的说明的后面隐藏着很多非常非常有用的信息,就像当年那个少林武僧把九阳真经隐藏在金刚经中一样。

点击过去后,第一句话就让我非常激动,它是这样说的:

Handles Win32 exceptions (C structured exceptions) as C++ typed exceptions.
直接翻译的话就是处理Win32异常(C风格结构化异常)像C++类型的异常,说白了就是使用C++异常风格处理C风格的异常,这正是我真正的目的,真正意义上的混用两种异常处理,使用C++风格的简单优雅,使用结构化异常的强大和高效。我在猜想微软是不是也有程序员像我一样遇到这样的问题,于是他们就发明了这个非常棒的方法?

这个函数的使用很简单就是设置一个处理结构化异常的函数指针,同时自己去实现这个函数。

_set_se_translator函数的原型如下:
_se_translator_function _set_se_translator(
   _se_translator_function seTransFunction
);
结构化异常处理函数的原型如下:
typedef void (*_se_translator_function)(unsigned int, struct _EXCEPTION_POINTERS* );
下面我就直接将MSDN中的例子代码放在这里,供大家参考,以防有些网友使用MSDN不熟悉看半天也找不到这个函数。
// crt_settrans.cpp
// compile with: /EHa
#include <stdio.h>
#include <windows.h>
#include <eh.h>
 
void SEFunc();
void trans_func( unsigned int, EXCEPTION_POINTERS* );
 
class SE_Exception
{
private:
    unsigned int nSE;
public:
    SE_Exception() {}
    SE_Exception( unsigned int n ) : nSE( n ) {}
    ~SE_Exception() {}
    unsigned int getSeNumber() { return nSE; }
};
int main( void )
{
    try
    {
        _set_se_translator( trans_func );
        SEFunc();
    }
    catch( SE_Exception e )
    {
        printf( "Caught a __try exception with SE_Exception./n" );
    }
}
void SEFunc()
{
    __try
    {
        int x, y=0;
        x = 5 / y;
    }
    __finally
    {
        printf( "In finally/n" );
    }
}
void trans_func( unsigned int u, EXCEPTION_POINTERS* pExp )
{
    printf( "In trans_func./n" );
    throw SE_Exception();
}
 
最后在我自己的项目中,我也使用了类似的设计风格,我定义了一个比这个例子中异常类更强大的异常类,最终做到了C++异常和结构化异常的完美结合。当然我的服务程序因此而变得异常健壮,所有的异常都被截获了,程序非常的稳定,至此服务程序的稳定性问题算是有一个好的解决方案了。当然我不能完全依赖于完善的异常处理机制,还是要将程序中固有的的错误解决的越多越好,这也是截获了异常后,要进一步做的工作。
希望此文真正的帮到了那些像我一样奋战在服务端程序开发一线的网友们!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值