关闭

转载:_set_se_translator 用法 + C++异常与windows异常

534人阅读 评论(0) 收藏 举报

使用c++异常时,包含对象编译不过,百思不解。补一补关于异常的知识
 
代码:
void func( )
{
        CString strTest;         // 错误!结构化异常无法解析C++ 对象
        __try{
           ...
        }
        __except(...){
                     ...
         }
}
编译信息:
warning C4509: nonstandard extension used: 'func' uses SEH and 'CString' has destructor
error C2712: Cannot use __try in functions that require object unwinding
 
这确实很令人费解,明明程序很简单的吗?而且程序中只用到了 SEH 异常模型的 try-except 语法,甚至 SEH 与 C++ 异常模型两者混合使用的情况都不存在。那么编译出错的原因究竟何在呢?
 
那原因就是: 同样还是由于在一个函数不能采用两种形式的异常处理机制而导致的编译错误。这岂不是更迷惑了。其实不然,这是因为: 在 C++ 异常处理模型中,为了能够在异常发生后,保证正确地释放相关的局部变量(也即调用析构函数),它必须要跟踪每一个“对象”的创建过程,这种由于异常产生而导致的对象析构的过程,被称为“ unwind ”。因此,如果一个函数中有局部对象的存在,那么它就一定会存在 C++ 的异常处理机制(也即会给此函数插入一些用于 C++ 异常处理“代码和信息”),这样,如果该函数中在再使用 try-except 机制,岂不是就冲突了吗?所以编译器也就报错了,因为它处理不了了。
 
附:
关于异常的文章
http://51cmm.csai.cn/ExpertEyes/No136.htm
...
http://51cmm.csai.cn/ExpertEyes/No167.htm
 
C++异常笔记
 ===================================================
C++异常和Windows结构异常的比较
Windows结构异常有如下几个特性:
1、它使用__try、__except、__finally和__leave关键字和RaiseException API;
2、它由Windows所支持,因此它不适合其它操作系统
3、它不处理C++对象的解析
说明:在使用Windows结构异常的函数内,如果有C++对象,编译器会发
出:error C2712: Cannot use __try in functions that require object unwinding 的错误。
如:
void fun( )
{
        CObject       object ;         // 错误!结构化异常无法解析C++ 对象
        __try{
           ...
        }
        __except(...){
                     ...
              }
}
4、它用为硬件异常(例如访问非法或被零除)或操作系统异常的结果被抛出。
       也可以作为RaiseException函数的结果被抛出;
 
而C++异常的特点是:
1、使用try、throw和catch等关键字;
2、它处理C++对象的解析;
3、它作为throw语句的结果被抛出;
 
注:MFC提供了第三种异常处理机制。它使用几个异常处理宏,这些宏现在也被编译成C++异常,因此没有必要在新的代码中使用它们!在MFC编程中,异
常对象都是从CExcept派生。大多数MFC异常处理对象都是动态分配的,因此当它们被捕获时,必须被删除;而没有捕获的MFC异常由MFC本身在AfxCa-
llWndProc函数中捕获并删除。
因为C++异常不能处理硬件和操作系统异常,因此需要将结构异常转化为
C++异常。
 
如何将结构异常转化为C++异常
Visual C++ 允许你通过使用_set_se_translator函数将结构异常转化为C++异常。
 
#include <eh.h>
class CSEHException
{
       public :
       CSEHException( UINT code , PEXCEPTION_POINTERS pep )
{
       m_exceptionCode      = code ;
       m_exceptionRecord   = *pep->ExceptionRecord ;
       m_context               = *pep->ContextRecord ;
       ASSERTE( m_exceptionCode == m_exceptionRecord.ExceptionCode );
}
operator unsigned int() { return m_exceptionCode ; }
 
UINT m_exceptionCode ;
EXCEPTION_RECORD   m_exceptionRecord ;
CONTEXT   m_context ;
} ;
 
// 结构化异常到C++异常转化器
void cdecl TranslateSEHtoCE( UINT code , PEXCEPTIONPOINTERS pep )
{
throw CSEHException( code , pep ) ;
}
 
int APIENTRY  WinMain( ……)
{
// 安装异常转化器
setse_translator( TranslateSEHtoCE ) ;
}
 
注意,异常转化器在每个线程的基础上进行工作,因此你需要为每一个线程安装一个转化器。这种异常转化器有一个副作用,你会在输出窗口的Debug标签中看见两个异常跟踪消息:一个是为了原来的结构异常,另一个是为了转化后的C++异常。使用了异常转化器后,你就可以像捕获C++异常一样捕获结构异常。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2688次
    • 积分:43
    • 等级:
    • 排名:千里之外
    • 原创:2篇
    • 转载:2篇
    • 译文:0篇
    • 评论:0条
    文章存档