C++异常处理几大秘诀

在调用catch块之前,把当前异常保存在exception_storage对象中,并注册一个专用于catch块的异常处理程序,,C++异常处理程序必须继续传就能得到exception_storage对象。

创新互联建站专业为企业提供向阳网站建设、向阳做网站、向阳网站设计、向阳网站制作等企业网站建设、网页设计与制作、向阳企业网站模板建站服务,10多年向阳做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。

现在重新回到C++异常处理这个主题上来。调用catch块时,它可能重新抛出异常或抛出新异常。前一种情况下,C++异常处理程序必须继续传播 (propagate)当前异常;后一种情况下,它需要在继续之前销毁原来的异常。

此时,处理程序要面对两个难题:"如何知道异常是源于catch块还是 程序的其他部分"和"如何跟踪原来的异常"。我的解决方法是:在调用catch块之前,把当前异常保存在exception_storage对象中,并注 册一个专用于catch块的C++异常处理程序——catch_block_protector。调用get_exception_storage()函数,就能得到exception_storage对象:

 
 
 
  1. namespace my_handler   
  2. {   
  3.     __declspec(dllexport) exception_storage* get_exception_storage() throw ()   
  4.     {   
  5.         void * p = TlsGetValue(dwstorage);   
  6.         return reinterpret_cast (p);   
  7.     }   
  8. }   
  9.  
  10.  
  11. BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )   
  12. {   
  13.     using my_handler::exception_storage;   
  14.     exception_storage *p;   
  15.     switch (ul_reason_for_call)   
  16.     {   
  17.     case DLL_PROCESS_ATTACH:   
  18.         //主线程(第一个线程)不会收到DLL_THREAD_ATTACH通知,所以,   
  19.         //与其相关的操作也放在这了   
  20.         dwstorage = TlsAlloc();   
  21.         if (-1 == dwstorage)   
  22.             return FALSE;   
  23.         p = new exception_storage();   
  24.         TlsSetValue(dwstorage, p);   
  25.         break ;   
  26.     case DLL_THREAD_ATTACH:   
  27.         p = new exception_storage();   
  28.         TlsSetValue(dwstorage, p);   
  29.         break;    
  30.     case DLL_THREAD_DETACH:   
  31.         p = my_handler::get_exception_storage();   
  32.         delete p;   
  33.         break ;   
  34.     case DLL_PROCESS_DETACH:   
  35.         p = my_handler::get_exception_storage();   
  36.         delete p;   
  37.         break ;   
  38.     }   
  39.     return TRUE;   
  40. }  

这样,当catch块(重新)抛出异常时,程序将会执行catch_block_protector。如果是抛出了新异常,这个函数可以从 exception_storage对象中分离出前一个异常并销毁它;如果是重新抛出原来的异常(可以通过ExceptionInformation数组 的前两个元素知道是新异常还是旧异常,后一种情况下着两个元素都是0,参见下面的代码),就通过拷贝ExceptionInformation数组来继续 传播它。下面的代码就是catch_block_protector()函数的实现。

在单线程程序中,这是一个完美的实现。但在多线程中,这就是个灾难了,想象一下多个线程访问它,并把异常对象保存在里面的情景吧。由于每个线程都有自己的 堆栈和C++异常处理链,我们需要一个线程安全的get_exception_storage实现:

每个线程都有自己单独的 exception_storage,它在线程启动时被创建,并在结束时被销毁。Windows提供的线程局部存储(thread local storage,TLS)可以满足这个要求,它能让每个线程通过一个全局键值来访问为这个线程所私有的对象副本,这是通过TlsGetValue()和 TlsSetValue这两个API来完成的。

Excptstorage.cpp中给出了get_exception_storage()函数的实现。它会被编译成动态链接库,因为我们可以籍此知道线 程的创建和退出——系统在这两种情况下都会调用所有(当前进程加载的)dll的DllMain()函数,这让我们有机会创建特定于线程的数据,也就是 exception_storage对象。

【编辑推荐】

  1. C与C++中标准输入实现方式上的一点区别
  2. C++编译器如何对Const常量进行分配存储空间
  3. C++类库设计的基本构思与方法
  4. 玩转C++语言的几种方法
  5. 如何更好的进行C++代码编制

网页题目:C++异常处理几大秘诀
本文URL:http://www.mswzjz.cn/qtweb/news32/103032.html

攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能