原文写的非常好,来自这里

一个函数如果说是“异常安全”的,必须同时满足以下两个条件:1.不泄漏任何资源;2.不允许破坏数据。 我们先通过两个反面的例子开始。

第一个是造成资源泄漏的例子。一个类Type,内含一个互斥锁成员 Mutex mutex,以及一个成员函数void Func()。假设Func函数的实现如下所示:

首先是获得互斥锁,中间是做该做的事,最后释放互斥锁。从功能上来讲很完整,没任何问题。但从异常安全角度来说,它却不满足条件。因为一旦DoSomething()函数内部导致异常,UnLock(&mutex)将不会被执行,于是互斥器将永远不会被释放了。换句话说即造成了资源泄漏。

再来看第二个造成数据破坏的例子。这个例子是我们很熟悉的重载 ‘=’ 操作符的成员函数。依然假设一个类Type,其中一个成员是一个指向一块资源(假设类型为T)的指针。这时候我们一般就需要来自定义复制构造函数和重载复制操作符以及析构函数了。(绝大多数情况下,这三个成员总是要么同时存在,要么都不用定义,因为编译器默认定义了,即C++中所谓的 ”Rule of 3" 规则。这里不作详细介绍)。这里我们只考虑重载复制操作符的问题,其部分代码假设如下:

首先来判断是否是自我复制,如果是,则直接返回自己。如果不是,则安全释放当前指向的资源,再创建一块与被复制的对象资源一模一样的资源并指向它,最后返回复制好的对象。同样,抛开异常安全来看,没问题。但是考虑到异常安全性时,一旦“new T(t->m_t)"时抛出异常,m_t将指向一块已被删除的资源,并没有真正指向一块与被复制的对象一样的资源。也就是说,原对象的数据遭到破坏。

C++中’异常安全函数”提供了三种安全等级:

1. 基本承诺:如果异常被抛出,对象内的任何成员仍然能保持有效状态,没有数据的破坏及资源泄漏。但对象的现实状态是不可估计的,即不一定是调用前的状态,但至少保证符合对象正常的要求。

2. 强烈保证:如果异常被抛出,对象的状态保持不变。即如果调用成功,则完全成功;如果调用失败,则对象依然是调用前的状态。

3. 不抛异常保证:函数承诺不会抛出任何异常。一般内置类型的所有操作都有不抛异常的保证。

如果一个函数不能提供上述保证之一,则不具备异常安全性。

现在我们来一个个解决上面两个问题。

对于资源泄漏问题,解决方法很容易,即用对象来管理资源。RAII技术之前介绍过,这里就不再赘述。我们在函数中不直接对互斥锁mutex进行操作,而是用到一个管理互斥锁的对象MutexLock ml。函数的新实现如下:

对象ml初始化后,自动对mutex上锁,然后做该做的事。最后我们不用负责释放互斥锁,因为ml的析构函数自动为我们释放了。这样,即时DoSomething()中抛出异常,ml也总是要析构的,就不用担心互斥锁不被正常释放的问题了。

对于第二个问题,一个经典的策略叫“copy and swap"。原则很简单:即先对原对象做出一个副本(copy),在副本上做必要的修改。如果出现任何异常,原对象依然能保证不变。如果修改成功,则通过不抛出任何异常的swap函数将副本和原对象进行交换(swap)。函数的新实现如下:

先创建一个被复制对象t的副本tmp,此时原对象尚未有任何修改,这样即使申请资源时有异常抛出,也不会影响到原对象。如果创建成功,则通过swap函数对临时对象的资源和原对象资源进行交换,标准库的swap函数承诺不抛出异常的,这样原对象将成功变成对象 t 的复制版本。对于这个函数,我们可以认为它是”强烈保证“异常安全的。

当然,提供强烈保证并不是总是能够实现的。一个函数能够提供的异常安全性等级,也取决于它的实现。考虑以下例子:

如果f1和f2都提供了”强烈保证“,则显然Func函数是具有”强烈保证“的安全等级。但是如果f1或f2中有一个不能提供,则Func函数将不再具备”强烈保证“等级,而是取决于f1和f2中安全等级最低的那个。

总结:

为了让代码具有更好的异常安全性,首先是”用对象来管理资源“,以避免资源的泄漏。其次,在异常安全性等级上,应该尽可能地往更高的等级上来限制。通过 copy-and-swap 方法往往可以实现”强烈保证“。但是我们也应该知道,”强烈保证“并不是对所有的情况都可实现,这取决于你在实现中用到的函数。函数提供的异常安全性的最高等级只能是你实现中调用的各个函数中异常安全性等级最低的那个。

参考:《Effective C++》,第三版。

C++中的异常安全性【转】的更多相关文章

  1. C++中的异常安全性

    http://blog.csdn.net/bonchoix/article/details/8046727 一个函数如果说是“异常安全”的,必须同时满足以下两个条件:1.不泄漏任何资源:2.不允许破坏 ...

  2. Java中的异常简介

    Java中异常的分类 Java中的异常机制是针对正常运行程序的一个必要补充,一般来说没有加入异常机制,程序也能正常运营,但是,由于入参.程序逻辑的严谨度,总会有期望之外的结果生成,因此加入异常机制的补 ...

  3. C++ 中的异常机制分析

    C++异常机制概述 异常处理是C++的一项语言机制,用于在程序中处理异常事件.异常事件在C++中表示为异常对象.异常事件发生时,程序使用throw关键字抛出异常表达式,抛出点称为异常出现点,由操作系统 ...

  4. PHP中Exception异常

    异常的基本使用 当异常被抛出时,其后的代码不会继续执行,PHP 会尝试查找匹配的 "catch" 代码块. 如果异常没有被捕获,而且又没用使用 set_exception_hand ...

  5. 【Java心得总结二】浅谈Java中的异常

    作为一个面向对象编程的程序员对于 下面的一句一定非常熟悉: try { // 代码块 } catch(Exception e) { // 异常处理 } finally { // 清理工作 } 就是面向 ...

  6. python虚拟机中的异常流控制

    异常:对程序运行中的非正常情况进行抽象.并且提供相应的语法结构和语义元素,使得程序员能够通过这些语法结构和语义元素来方便地描述异常发生时的行为. 1.Python中的异常机制: 1.1Python虚拟 ...

  7. Python中获取异常(Exception)信息

    异常信息的获取对于程序的调试非常重要,可以有助于快速定位有错误程序语句的位置.下面介绍几种python中获取异常信息的方法,这里获取异常(Exception)信息采用try...except...程序 ...

  8. Java中测试异常的多种方式

    使用JUnit来测试Java代码中的异常有很多种方式,你知道几种? 给定这样一个class. Person.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  9. Atitit 数据处理查询 中的异常标准化草案 jpa jdbc hb  oql规范attilax总结

    Atitit 数据处理查询 中的异常标准化草案 jpa jdbc hb  oql规范attilax总结 Javaee6 与net 异常规范1 Jpa规范 JPA全称Java Persistence A ...

随机推荐

  1. 用Visual C#创建Windows服务程序

    一.Windows服务介绍: Windows服务以前被称作NT服务,是一些运行在Windows NT.Windows 2000和Windows XP等操作系统下用户环境以外的程序.在以前,编写Wind ...

  2. (原)tslib的交叉编译

    今天准备重新来交叉编译qt5.3.1的源码,由于按网上说的,需要先编译tslib,所以拿起来之前的编译源码,打算重新用新的交叉编译工具再次编译一次,在查找资料的过程中浪费了些许时间.其实直接就在使用s ...

  3. Ubuntu 14.04 安装 DevStack与遇到的的问题记录

    本文总结Ubuntu 14.04下部署DevStack的过程以及一些可能遇到的问题. 一.安装 以下的操作最好在普通用户下进行,至少在git clone devstack的时候使用普通用户,这样可以避 ...

  4. Xianfeng轻量级Java中间件平台:流水号管理、组织机构管理

    流水号管理:现实中,经常都会和流水号打交道,至于什么是流水号,简而言之,就是按照特定格式要求产生的一个号码,并且总是按照递增的规则生成的,对于要求比较高的业务,需要流水号是连续的,比如移动营业厅排号小 ...

  5. DNS Bind服务配置解析

    DNS域名解析服务(Domain Name System)是用于解析域名与IP地址对应关系的服务,功能上可以实现正向解析与反向解析: 一.DNS服务器工作模式分类: 1.主服务器:在特定区域内具有唯一 ...

  6. python模块之 - subprocess执行unix/linux命令

    subprocess模块提供了一种一致的方法来创建和处理附加进程,与标准库中的其它模块相比,提供了一个更高级的接口,subprocess模块用来生成子进程,并可以通过管道连接它们的输入/输出/错误,以 ...

  7. VIM选择文本块/复制/粘贴

    在正常模式下(按ESC进入)按键v进入可视化模式,然后按键盘左右键或h,l键即可实现文本的选择.其它相关命令:v:按字符选择.经常使用的模式,所以亲自尝试一下它. V:按行选择.这在你想拷贝或者移动很 ...

  8. tRNAscan-SE 预测tRNA基因

    tRNAscan-SE 软件可以根据输入的基因组序列,预测对应的tRNA的基因 在线的tRNAscan-SE的链接如下:http://lowelab.ucsc.edu/tRNAscan-SE/ 如下图 ...

  9. pyremotevbox 用法

    >>> import pyremotevbox.vbox as vbox >>> host = vbox.VirtualBoxHost(host='10.0.2.2 ...

  10. Linux 下 Nginx 反向代理 负载均衡配置

    转载请注明出处:http://blog.csdn.net/smartbetter/article/details/52036350 上一篇分享了 Nginx + JDK + Tomcat + MySQ ...