• 5363阅读
  • 1回复

Jisong's C++ Extention - Try to Keep Alive [复制链接]

上一主题 下一主题
离线beajisong
 

只看楼主 倒序阅读 楼主  发表于: 2010-05-06
Jisong's C++ Extention - Try to Keep Alive
大学刚学java时发现,java什么东西都是异常,天天要try,不过有一点倒是非常不错,空指针异常之类的都可以搞定。于是我后来就想到了C++

是不是也能这样做。后来,翻看了许多文章,发现Windows下,可以通过__try那套做,不过我觉得不通用,所以自己就研究了起来。其实很久之

前就做完了,但是,懒得写心的,但出于知识共享精神,今天还是写出来吧,希望能有抛砖引玉的效果。

还是一贯的风格,大家先想想,如果这套东西做出来了,得怎么用着方便。我觉得尽量要符合原来的try-catch行为。那样的话,我的设想是这

样的。
    char *p = NULL ;

    gtry {
        *p = 'a' ;
    } gcatch (GException& e) {
        GDebug(e.toString()) ;
    }

怎么样?和原来的东西是一样的吧,也就是多了个g字。有的人其实做过这个,但不是在C++中,而是在纯C里面。C语言可以用下面的东西做。
    signal( SIGSEGV, __gSEGVHandler ) ;

这样就可以处理SIGSEGV段异常信号,然后进行解救了。当然还有大家比较少接触的一套C的东西,setjmp和longjmp函数。这两个函数一个是保

存当前栈状态,一个是恢复到某个栈状态的。
我们先看看gtry是怎么做的吧~
    #define gtry    try { \
                    GJumpContainer* container = new GJumpContainer(); \ 1
                    int __jumpReturn = sigsetjmp(*(_g_jump_buffer_t*)(container->getBuffer()), 1) ; \ 2
                    if(!__jumpReturn) {\ 3
                        GJumpManager::getManager().push(container); \ 4
                    } else { \
                        GJumpManager::getManager().pop() ; \ 5
                        __gThrowException(__jumpReturn) ; \ 6
                    } 7
                //    {
                //        any thing....
                //    }
首先,他是个宏,然后里面其实还是个try。先看1,建立了一个跳转容器,其实这个容器就是用来保存栈状态的。
GJumpContainer::GJumpContainer()
{
    jumpBuffer = (_g_jump_buffer_t*)malloc(sizeof(_g_jump_buffer_t));
}

GJumpContainer::~GJumpContainer()
{
    free(jumpBuffer);
}

_g_jump_buffer_t*& GJumpContainer::getBuffer()
{
    return jumpBuffer;
}
然后就是2,这里有两个作用。听起来有点别扭,大家慢慢理解,我语言能力特别有限。在第一次进入这里时,就是说按你正常逻辑执行时,这

个东西会将现场保存起来,并返回一个0值。那样条件3就成立了。语句4就会将现场快照保存到当前线程对应的一个缓存里。
void GJumpManager::push(GJumpContainer* jumpContainer)
{
    jumStackMap[QThread::currentThread()].push(jumpContainer);
}
语句7后面根的就是你要try的代码了,如果这个代码导致段错误,程序崩溃了,这里就重新会返回到2处,回复当时保存的这个现场,2会返回一

个可控制的值给变来那个,条件3就进入到语句5那里执行。他会撇掉保存的现场,然后根据值来产生一个真正的异常出来,这样就会直接跳到

catch里执行了。

好了,try完事儿了,看看我们的gcatch吧~~
#define gcatch(exp)    GJumpManager::getManager().pop(); \ 1
                    } catch(exp) 2
这个简单,就两句话。先看第一句,语句1就是为了,如果这个程序没崩溃,就把原来保留的现场扔掉,这样的话这个东东就可以有嵌套能力了

。语句2就是常规的catch,没啥好说的,接受异常而已。后面就是靠你自己处理异常啦~~~

好,到这里,表面功夫已经做足。得看看崩溃时到底是怎么挽救的我们的程序了。
void __gSEGVHandler( int sig)
{
    //Here should not include object creating or stream i/o operation.
    siglongjmp(*(_g_jump_buffer_t*)(GJumpManager::getManager().getJumpContainer()->getBuffer()), G_POINTER_EXCEPTION);
}
就是这个函数作为了我们的崩溃处理函数,如果遇到段异常时就会调用它,但是,你可千万不要以为在这里可以为所欲为。这时,我们应用程序

的小命接近驾崩,应用程序的栈也并不是完整的了。看那句注释(英语巨烂,别怪我),告诉我们这里不许创建任何形式的对象,或者执行任何

形式的流操作,你连想Debug都只能直接输出。为什么?因为现在如果你创建了,这个东西这辈子都不会销毁,因为栈会在随后立即被还原成原

来的样子,你在乱动两下,上帝都得拿你没招儿!看最后一个参数,G_POINTER_EXCEPTION这个就是可以让setjmp返回的返回值。通过这个值我

们就可以知道,原来发生的是段异常啊!

好了,基本也就是这么多,还有一个需要提醒你的是,最好不要在gtry里面创建对象,因为这个对象很有可能没有得到销毁的机会。内存泄露等

等问题会马上到来。所以,gtry里面就放要测试的那一句就OK了。当然,你要new东西应该还是没问题的。

我是苍松,很多时也写英文Jisong,欢迎大家交流,我就在Qt的群里窝着。

各位,下次见吧,看看有啥值得分享的我会再写的。
离线beajisong

只看该作者 1楼 发表于: 2010-05-11
自顶
快速回复
限100 字节
 
上一个 下一个