| 订阅 | 在线投稿
分享
 
 
 

Linux 下 C++程序的异常处理技巧

2008-06-01 02:06:09 编辑來源:互联网 国际版 评论
 
 
  处理 C++ 中的异常会在语言级别上碰到少许隐含限制,但在某些情况下,您可以绕过它们。学习各种利用异常的方法,您就可以生产更可靠的应用程序。

  保留异常来源信息

  在 C++中,无论何时在处理程序内捕捉一个异常,关于该异常来源的信息都是不为人知的。异常的具体来源可以提供许多更好地处理该异常的重要信息,或者提供一些可以附加到错误日志的信息,以便以后进行分析。

  为了解决这一问题,可以在抛出异常语句期间,在异常对象的构造函数中生成一个堆栈跟踪。ExceptionTracer 是示范这种行为的一个类。

  清单 1. 在异常对象构造函数中生成一个堆栈跟踪

  

  // Sample Program:

  // Compiler: gcc 3.2.3 20030502

  // Linux: Red Hat

  #include <execinfo.h>

  #include <signal.h>

  #include <exception>

  #include <iostream>

  using namespace std;

  /////////////////////////////////////////////

  class ExceptionTracer

  {

  public:

  ExceptionTracer()

  {

  void * array[25];

  int nSize = backtrace(array, 25);

  char ** symbols = backtrace_symbols(array, nSize);

  for (int i = 0; i < nSize; i++)

  {

  cout << symbols[i] << endl;

  }

  free(symbols);

  }

  };

  治理信号

  每当进程执行一个令人讨厌的动作,以致于 Linux? 内核发出一个信号时,该信号都必须被处理。信号处理程序通常会释放一些重要资源并终止应用程序。在这种情况下,堆栈上的所有对象实例都处于未破坏状态。另一方面,假如这些信号被转换成 C++ 异常,那么您可以优雅地调用其构造函数,并安排多层 catch 块,以便更好地处理这些信号。

  清单 2 中定义的 SignalExceptionClass,提供了表示内核可能发出信号的 C++ 异常的抽象。SignalTranslator 是一个基于 SignalExceptionClass 的模板类,它通常用来实现到 C++ 异常的转换。在任何瞬间,只能有一个信号处理程序处理一个活动进程的一个信号。因此,SignalTranslator 采用了 singleton 设计模式。整体概念通过用于 SIGSEGV 的 SegmentationFault 类和用于 SIGFPE 的 FloatingPointException 类得到了展示。

  清单 2. 将信号转换成异常

  template <class SignalExceptionClass> class SignalTranslator

  {

  private:

  class SingleTonTranslator

  {

  public:

  SingleTonTranslator()

  {

  signal(SignalExceptionClass::GetSignalNumber(), SignalHandler);

  }

  static void SignalHandler(int)

  {

  throw SignalExceptionClass();

  }

  };

  public:

  SignalTranslator()

  {

  static SingleTonTranslator s_objTranslator;

  }

  };

  // An example for SIGSEGV

  class SegmentationFault : public ExceptionTracer, public exception

  {

  public:

  static int GetSignalNumber() {return SIGSEGV;}

  };

  SignalTranslator<SegmentationFault> g_objSegmentationFaultTranslator;

  // An example for SIGFPE

  class FloatingPointException : public ExceptionTracer, public exception

  {

  public:

  static int GetSignalNumber() {return SIGFPE;}

  };

  SignalTranslator<FloatingPointException> g_objFloatingPointExceptionTranslator;

  治理构造函数和析构函数中的异常

  在全局(静态全局)变量的构造和析构期间,每个 ANSI C++ 都捕捉到异常是不可能的。因此,ANSI C++ 不建议在那些其实例可能被定义为全局实例(静态全局实例)的类的构造函数和析构函数中抛出异常。换一种说法就是永远都不要为那些其构造函数和析构函数可能抛出异常的类定义全局(静态全局)实例。不过,假如假定有一个特定编译器和一个特定系统,那么可能可以这样做,幸运的是,对于 Linux 上的 GCC,恰好是这种情况。

  使用 ExceptionHandler 类可以展示这一点,该类也采用了 singleton 设计模式。其构造函数注册了一个未捕捉的处理程序。因为每次只能有一个未捕捉的处理程序处理一个活动进程,构造函数应该只被调用一次,因此要采用 singleton 模式。应该在定义有问题的实际全局(静态全局)变量之前定义 ExceptionHandler 的全局(静态全局)实例。

  清单 3. 处理构造函数中的异常

  

  

  class ExceptionHandler

  {

  private:

  class SingleTonHandler

  {

  public:

  SingleTonHandler()

  {

  set_terminate(Handler);

  }

  static void Handler()

  {

  // Exception from constrUCtion/destruction of global variables

  try

  {

  // re-throw

  throw;

  }

  catch (SegmentationFault &)

  {

  cout << "SegmentationFault" << endl;

  }

  catch (FloatingPointException &)

  {

  cout << "FloatingPointException" << endl;

  }

  catch (...)

  {

  cout << "Unknown Exception" << endl;

  }

  //if this is a thread performing some core activity

  abort();

  // else if this is a thread used to service requests

  // pthread_exit();

  }

  };

  public:

  ExceptionHandler()

  {

  static SingleTonHandler s_objHandler;

  }

  };

  //////////////////////////////////////////////////////////////////////////

  class A

  {

  public:

  A()

  {

  //int i = 0, j = 1/i;

  *(int *)0 = 0;

  }

  };

  // Before defining any global variable, we define a dummy instance

  // of ExceptionHandler object to make sure that

  // ExceptionHandler::SingleTonHandler::SingleTonHandler() is invoked

  ExceptionHandler g_objExceptionHandler;

  A g_a;

  //////////////////////////////////////////////////////////////////////////

  int main(int argc, char* argv[])

  {

  return 0;

  }

  处理多线程程序中的异常

  有时一些异常没有被捕捉,这将造成进程异常中止。不过很多时候,进程包含多个线程,其中少数线程执行核心应用程序逻辑,同时,其余线程为外部请求提供服务。假如服务线程因编程错误而没有处理某个异常,则会造成整个应用程序崩溃。这一点可能是不受人们欢迎的,因为它会通过向应用程序传送不合法的请求而助长拒绝服务攻击。为了避免这一点,未捕捉处理程序可以决定是请求异常中止调用,还是请求线程退出调用。清单 3 中 ExceptionHandler::SingleTonHandler::Handler() 函数的末尾处展示了该处理程序。

  结束语

  本文简单地讨论了少许 C++ 编程设计模式,以便更好地执行以下任务:

  ·在抛出异常的时候追踪异常的来源。

  ·将信号从内核程序转换成 C++ 异常。

  ·捕捉构造和/或析构全局变量期间抛出的异常。

  ·多线程进程中的异常处理。
 
 
处理 C++ 中的异常会在语言级别上碰到少许隐含限制,但在某些情况下,您可以绕过它们。学习各种利用异常的方法,您就可以生产更可靠的应用程序。 保留异常来源信息 在 C++中,无论何时在处理程序内捕捉一个异常,关于该异常来源的信息都是不为人知的。异常的具体来源可以提供许多更好地处理该异常的重要信息,或者提供一些可以附加到错误日志的信息,以便以后进行分析。 为了解决这一问题,可以在抛出异常语句期间,在异常对象的构造函数中生成一个堆栈跟踪。ExceptionTracer 是示范这种行为的一个类。 清单 1. 在异常对象构造函数中生成一个堆栈跟踪 // Sample Program: // Compiler: gcc 3.2.3 20030502 // Linux: Red Hat #include <execinfo.h> #include <signal.h> #include <exception> #include <iostream> using namespace std; ///////////////////////////////////////////// class ExceptionTracer {  public: ExceptionTracer() {  void * array[25];  int nSize = backtrace(array, 25);  char ** symbols = backtrace_symbols(array, nSize);    for (int i = 0; i < nSize; i++)  { cout << symbols[i] << endl;  } free(symbols);  } }; 治理信号 每当进程执行一个令人讨厌的动作,以致于 Linux? 内核发出一个信号时,该信号都必须被处理。信号处理程序通常会释放一些重要资源并终止应用程序。在这种情况下,堆栈上的所有对象实例都处于未破坏状态。另一方面,假如这些信号被转换成 C++ 异常,那么您可以优雅地调用其构造函数,并安排多层 catch 块,以便更好地处理这些信号。 清单 2 中定义的 SignalExceptionClass,提供了表示内核可能发出信号的 C++ 异常的抽象。SignalTranslator 是一个基于 SignalExceptionClass 的模板类,它通常用来实现到 C++ 异常的转换。在任何瞬间,只能有一个信号处理程序处理一个活动进程的一个信号。因此,SignalTranslator 采用了 singleton 设计模式。整体概念通过用于 SIGSEGV 的 SegmentationFault 类和用于 SIGFPE 的 FloatingPointException 类得到了展示。 清单 2. 将信号转换成异常 template <class SignalExceptionClass> class SignalTranslator {  private: class SingleTonTranslator {  public: SingleTonTranslator() {  signal(SignalExceptionClass::GetSignalNumber(), SignalHandler); } static void SignalHandler(int) {  throw SignalExceptionClass(); }  };  public: SignalTranslator() {  static SingleTonTranslator s_objTranslator; } }; // An example for SIGSEGV class SegmentationFault : public ExceptionTracer, public exception {  public: static int GetSignalNumber() {return SIGSEGV;} }; SignalTranslator<SegmentationFault> g_objSegmentationFaultTranslator; // An example for SIGFPE class FloatingPointException : public ExceptionTracer, public exception {  public: static int GetSignalNumber() {return SIGFPE;} }; SignalTranslator<FloatingPointException> g_objFloatingPointExceptionTranslator; 治理构造函数和析构函数中的异常 在全局(静态全局)变量的构造和析构期间,每个 ANSI C++ 都捕捉到异常是不可能的。因此,ANSI C++ 不建议在那些其实例可能被定义为全局实例(静态全局实例)的类的构造函数和析构函数中抛出异常。换一种说法就是永远都不要为那些其构造函数和析构函数可能抛出异常的类定义全局(静态全局)实例。不过,假如假定有一个特定编译器和一个特定系统,那么可能可以这样做,幸运的是,对于 Linux 上的 GCC,恰好是这种情况。 使用 ExceptionHandler 类可以展示这一点,该类也采用了 singleton 设计模式。其构造函数注册了一个未捕捉的处理程序。因为每次只能有一个未捕捉的处理程序处理一个活动进程,构造函数应该只被调用一次,因此要采用 singleton 模式。应该在定义有问题的实际全局(静态全局)变量之前定义 ExceptionHandler 的全局(静态全局)实例。 清单 3. 处理构造函数中的异常 class ExceptionHandler {  private: class SingleTonHandler {  public: SingleTonHandler() {  set_terminate(Handler); } static void Handler() {  // Exception from constrUCtion/destruction of global variables  try  { // re-throw throw;  }  catch (SegmentationFault &)  { cout << "SegmentationFault" << endl;  }  catch (FloatingPointException &)  { cout << "FloatingPointException" << endl;  }  catch (...)  { cout << "Unknown Exception" << endl;  }  //if this is a thread performing some core activity  abort();  // else if this is a thread used to service requests  // pthread_exit(); } }; public:  ExceptionHandler()  { static SingleTonHandler s_objHandler;  } }; ////////////////////////////////////////////////////////////////////////// class A {  public: A() {  //int i = 0, j = 1/i;  *(int *)0 = 0; } }; // Before defining any global variable, we define a dummy instance // of ExceptionHandler object to make sure that // ExceptionHandler::SingleTonHandler::SingleTonHandler() is invoked ExceptionHandler g_objExceptionHandler; A g_a; ////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) {  return 0; } 处理多线程程序中的异常 有时一些异常没有被捕捉,这将造成进程异常中止。不过很多时候,进程包含多个线程,其中少数线程执行核心应用程序逻辑,同时,其余线程为外部请求提供服务。假如服务线程因编程错误而没有处理某个异常,则会造成整个应用程序崩溃。这一点可能是不受人们欢迎的,因为它会通过向应用程序传送不合法的请求而助长拒绝服务攻击。为了避免这一点,未捕捉处理程序可以决定是请求异常中止调用,还是请求线程退出调用。清单 3 中 ExceptionHandler::SingleTonHandler::Handler() 函数的末尾处展示了该处理程序。 结束语 本文简单地讨论了少许 C++ 编程设计模式,以便更好地执行以下任务: ·在抛出异常的时候追踪异常的来源。 ·将信号从内核程序转换成 C++ 异常。 ·捕捉构造和/或析构全局变量期间抛出的异常。 ·多线程进程中的异常处理。
󰈣󰈤
日版宠物情人插曲《Winding Road》歌词

日版宠物情人2017的插曲,很带节奏感,日语的,女生唱的。 最后听见是在第8集的时候女主手割伤了,然后男主用嘴帮她吸了一下,插曲就出来了。 歌手:Def...

兄弟共妻,我成了他们夜里的美食

老钟家的两个儿子很特别,就是跟其他的人不太一样,魔一般的执着。兄弟俩都到了要结婚的年龄了,不管自家老爹怎么磨破嘴皮子,兄弟俩说不娶就不娶,老父母为兄弟两操碎了心...

网络安全治理:国家安全保障的主要方向是打击犯罪,而不是处置和惩罚受害者

来源:中国青年报 新的攻击方法不断涌现,黑客几乎永远占据网络攻击的上风,我们不可能通过技术手段杜绝网络攻击。国家安全保障的主要方向是打击犯罪,而不是处置和惩罚...

 
 
 
>>返回首页<<
 为你推荐
 
 
 
 转载本文
 UBB代码 HTML代码
复制到剪贴板...
 
 
 热帖排行
 
单纯美女 迷人女孩
校园甜美少女
忍辱负重
大学校园
 
 
王朝网络微信公众号
微信扫码关注本站公众号wangchaonetcn
 
  免责声明:本文仅代表作者个人观点,与王朝网络无关。王朝网络登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
©2005- 王朝网络 版权所有