C++异常~二 转
Linux 下 C++ 异常处理技巧
处理固有语言局限性的四种技术
处理 C++ 中的异常会在语言级别上遇到少许隐含限制,但在某些情况下,您可以绕过它们。学习各种利用异常的方法,您就可以生产更可靠的应用程序。
1 评论
保留异常来源信息
在 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++异常~二 转的更多相关文章
- java提高篇(十七)-----异常(二)
承接上篇博文:java提高篇-----异常(一) 五.自定义异常 Java确实给我们提供了非常多的异常,但是异常体系是不可能预见所有的希望加以报告的错误,所以Java允许我们自定义异常来表 ...
- java 异常二
一 捕获异常try…catch…finally 捕获:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理 捕获异常格式: try { //需要被检测的语句. } catch(异 ...
- Java异常(二) 《Effective Java》中关于异常处理的几条建议
概要 本章是从<Effective Java>摘录整理出来的关于异常处理的几条建议.内容包括:第1条: 只针对不正常的情况才使用异常第2条: 对于可恢复的条件使用被检查的异常,对于程序错误 ...
- 【C++】异常简述(二):C++的异常处理机制
上文简述了在C语言中异常的处理机制,本文主要讲解C++中的异常处理. 一.异常的语法格式 在C++中,异常的抛出和处理主要使用了以下三个关键字:try. throw . catch.其格式如下: 当我 ...
- Hibernate 非常见异常集合
异常一:org.hibernate.AnnotationException: Collection has neither generic type or OneToMany.targetEntity ...
- hadoop安装遇到的各种异常及解决办法
hadoop安装遇到的各种异常及解决办法 异常一: 2014-03-13 11:10:23,665 INFO org.apache.hadoop.ipc.Client: Retrying connec ...
- [转]菜鸟程序员之Asp.net MVC Session过期异常的处理
本文转自:http://www.cnblogs.com/JustRun1983/p/3377652.html 小赵是刚毕业的计算机专业方面的大学生,4年的大学时间里面,他读过了很多编程方面的数据,也动 ...
- 构建spring+mybatis+redis架构时遇到的小异常
异常一: Caused by: java.lang.NoSuchMethodError: org.springframework.beans.BeanUtils.instantiateClass(Lj ...
- 解决jetty7.0.pre5启动时报ClassNotFoundException: javax.interceptor.InvocationContext异常的问题
一.背景介绍:最近项目在使用maven命令行运行jetty服务器时出现ClassNotFoundException: javax.interceptor.InvocationContext异常 二.环 ...
随机推荐
- Android中StackOverflow的问题
最近出现了一个让人抓狂的问题. 现在的项目中,制作了一个界面非常复杂.Fragment中嵌套下拉刷新的Listview 这样一个布局,在3.0以上的手机上都表现良好问题!但是在2.x的比较弱爆的手机上 ...
- Qt 编译时遇到 error: [debug/qrc_music.cpp] Error 1
第一种方式,清理编译文件 把Qdebug release 文件件都删除, 删除makefile 文件 尝试重新编译 以上是网上寻找的结果 以下是我的解决方法 如果还抱错,请检查qrc文件是否存在异常 ...
- Python 3.6 爬取BD电影网
2018-07-10 #coding:utf-8 #coding:utf-8 from lxml import etree import requests import pandas import t ...
- 官方文档 恢复备份指南五 Configuring the RMAN Environment
本章内容: Configuring the Environment for RMAN Backups 配置RMAN环境 Configuring RMAN to Make Backups to a ...
- 最大流——EK算法
一.算法理论 [基本思想] 反复寻找源点s到汇点t之间的增广路径,若有,找出增广路径上每一段[容量-流量]的最小值delta,若无,则结束.在寻找增广路径时,可以用BFS来找,并且更新残留网络的值(涉 ...
- vs2017切换设计、拆分假死的解决
今天安装了vs2017版把vs2015卸载了,原因就是vs2015运行webform后ajaxpro总是会出现time out现象.太难受了,所以决定体验一下新版本. 安装了vs2017后ajaxpr ...
- 第四次JAVA作业
public class TvbDog { public static void main(String[] args) { Dog per=new Dog("陈狗"," ...
- Redis数据类型及操作详解
Redis数据库,是nosql的一种.与传统关系型数据库(如mysql.sqlserver等)相比,他在处理大数据量上相当有优势,扩展性和可用性高,这是传统型数据库所达不到的. Redis是一个key ...
- 【log4net】- 日志使用教程
一.log4net简介: 1. Log4net的优点: 几乎所有的大型应用都会有自己的用于跟踪调试的API.因为一旦程序被部署以后,就不太可能再利用专门的调试工具了.然而一个管理员可能需要有一套强大的 ...
- javascript 数组以及对象的深拷贝
如果 let arr2 = arr1: 那么只是赋值的引用,改变arr2也会相应的改变arr1: 如果 let arr2 = [].concat(arr1): 如果arr1里面不是引用类型,那么ar ...