转自:http://www.cnblogs.com/zgfLawliet/p/3417308.html

 

异常安全的代码是指,满足两个条件

1异常中立性 :

是指当你的代码(包括你调用的代码)引发异常时,这个异常 能保持原样传递到外层调用代码

2.异常安全性:

  • 抛出异常后,资源不泄露,
  • 抛出异常后,不会使原有数据恶化(例如正常指针变野指针)
  • 少些try catch,因为大量的try catch会影响代码逻辑。导致代码丑陋混乱不优雅

 

一段代码要具有异常安全性,必须同时具有异常中立性和一定等级的异常安全性保证

异常安全的等级一般有:

1,函数提供基本保证(the basic guarantee)(不会发生内存泄漏并且程序内的每个对象都处在合法的状态,没有流错位,没有野指针,但是不是每个对象的精确状态是可以预期的,如可能发生异常后,指针处在空指针状态,或者某种默认状态,但是客户无法预知到底是哪一个),对于达成基本保证可以多使用智能指针来管理资源

2,函数提供强力保证(the strong guarantee),强力保证含义是,成功或者回滚保证,发生异常的函数对程序来说,没有任何改动,提供发生异常时候的回滚机制。

调用提供强力保证的函数之后,仅有两种可能的程序状态:像预期一样成功执行了函数,或者函数回滚继续保持函数被调用时当时的状态。与之相比,如果调用只提供基本保证的函数引发了异常,程序可能存在于任何合法的状态。

函数提供强力保证的有效解决办法是

copy-and-swap:

先做出一个你要改变的对象的copy,然后在这个copy上做出全部所需的改变。如果改变过程中的某些操作抛出了异常,最初的对象保持不变。在所有的改变完全成功之后,将被改变的对象和最初的对象在一个不会抛出异常的操作中进行swap。

3. 函数有不抛出保证(the nothrow guarantee),对于所有对内建类型(例如,ints,指针,等等)的操作都是不抛出(nothrow)的(也就是说,提供不抛出保证)。这是异常安全代码中必不可少的基础构件。

注意事项:

异常安全 最关键的是:swap ctor dctor 不发生异常保证,只有成功或者终止程序两种状态

一个函数的异常安全等级,是取决于它所调用的函数中最低异常安全等级的函数。

C++11新增了noexcept关键字,在void func() noexcept{}noexcept保证了这个函数不会抛出异常,只有终止程序和成功执行两种状态。

noexcept可以接受一个常量表达式,noexcept(constexpr。。。)当常量表达式为转换为true说明该函数保证不抛出异常。

从异常安全的观点看,不抛出的函数(nothrow functions)是极好的,但是在 C++ 的 C 部分之外部不调用可能抛出异常的函数简直就是寸步难行。使用动态分配内存的任何东西(例如,所有的 STL 容器)如果不能找到足够的内存来满足一个请求,在典型情况下,它就会抛出一个 bad_alloc 异常。只要你能做到就提供不抛出保证,但是对于大多数函数,选择是在基本的保证和强力的保证之间的。

但是,不是所有函数都能做出异常保证的,考虑这样一个函数,函数内部的函数内是一个对数据库的操作,一旦异常发生,难以撤销对数据库的更改。如果想对这样的函数做到异常的strong guarantee保证,就是非常困难度事情。

所以对于只对局部变量改变的函数保证异常安起会相对比较容易。如果函数的操作中牵扯到全局变量等等,就变得困难的多。

解决异常安全的好办法:

1,多使用RAII,使用智能指针来管理内存。由于unwind机制的保证,当异常发生时,函数栈内已构造的局部对象的析构函数会被一一调用,在析构函数内释放资源,也就杜绝了内存泄漏的问题。

2,做好程序设计。特别是异常发生时的回滚机制的正确使用,copy-and-swap是有效的方法。

3,注意需要异常保证的函数内部的调用函数,异常安全等级是以有最低等级异常保证的函数确定的。

一个系统即使只有一个函数不是异常安全的,那么系统作为一个整体就不是异常安全的,因为调用那个函数可能发生泄漏资源和恶化数据结构。

4,对于一些需要保证性能的程序,在提供基本的异常安全时,要注意,栈解退机制只是调用析构函数,对于内置类型的操作不会被回滚,所以。像起累加器作用的一些内置类型变量,应该注意在函数成功执行后再进行累加。避免数据结构恶化。重新分配资源给原本已经持有资源的变量,应该先清空释放变量的资源,指针再设置为nullptr,防止资源重新分配过程中抛出异常,导致指针变为野指针的问题。

5,流对象,资源对象,new对象,不应该直接作为参数,一旦抛出异常,就可能会导致严重的问题,函数也许会被错误的执行,资源也许会泄漏。对于函数参数和函数内使用的全局变量,应该保证在进入函数内部是是正常状态。

6.减少全局变量的使用,对包含全局变量的函数做异常安全是比较困难的事情,栈解退也只对局部变量起效果。

7,如果不知道如何处理异常,就不要捕获异常,直接终止比吞掉异常不处理要好

8.保证 构造 析构 swap不会失败

这里有个注意事项:

在构造函数中,如果抛出异常,是不会调用当前正在构造的类的析构函数的,因为当前正在构造的类没有构造完成,只会析构已经构造完成成员和父类,So,极易导致内存泄漏,这里要谨慎处理,使用RAII,智能指针,noexcept保证不会抛出异常和恶化数据。

 

参考文章:

1:对象生死劫-构造函数和析构函数异常

http://blog.csdn.net/leadzen/article/details/1783116

2:C++箴言:争取异常安全的代码

http://dev.yesky.com/490/2087990.shtml

3:如何编写异常安全的代码

http://blog.csdn.net/wingfiring/article/details/660900

C++异常安全的更多相关文章

  1. alias导致virtualenv异常的分析和解法

    title: alias导致virtualenv异常的分析和解法 toc: true comments: true date: 2016-06-27 23:40:56 tags: [OS X, ZSH ...

  2. ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”

    在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...

  3. 记一次tomcat线程创建异常调优:unable to create new native thread

    测试在进行一次性能测试的时候发现并发300个请求时出现了下面的异常: HTTP Status 500 - Handler processing failed; nested exception is ...

  4. 使用JSONObject.fromObject的时候出现“There is a cycle in the hierarchy”异常 的解决办法

    在使用JSONObject.fromObject的时候,出现“There is a cycle in the hierarchy”异常.   意思是出现了死循环,也就是Model之间有循环包含关系: ...

  5. SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论

    异常汇总:http://www.cnblogs.com/dunitian/p/4523006.html#signalR 后台创建了一个DntHub的集线器 前台在调用的时候出现了问题(经检查是代理对象 ...

  6. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  7. [C#] C# 知识回顾 - 学会处理异常

    学会处理异常 你可以使用 try 块来对你觉得可能会出现异常的代码进行分区. 其中,与之关联的 catch 块可用于处理任何异常情况. 一个包含代码的 finally 块,无论 try 块中是否在运行 ...

  8. [C#] C# 知识回顾 - 学会使用异常

    学会使用异常 在 C# 中,程序中在运行时出现的错误,会不断在程序中进行传播,这种机制称为“异常”. 异常通常由错误的代码引发,并由能够更正错误的代码进行 catch. 异常可由 .NET 的 CLR ...

  9. [C#] C# 知识回顾 - 异常介绍

    异常介绍 我们平时在写程序时,无意中(或技术不够),而导致程序运行时出现意外(或异常),对于这个问题, C# 有专门的异常处理程序. 异常处理所涉及到的关键字有 try.catch 和 finally ...

  10. 基于AOP的MVC拦截异常让代码更优美

    与asp.net 打交道很多年,如今天微软的优秀框架越来越多,其中微软在基于mvc的思想架构,也推出了自己的一套asp.net mvc 框架,如果你亲身体验过它,会情不自禁的说‘漂亮’.回过头来,‘漂 ...

随机推荐

  1. 分分钟钟学会Python -基础&运算符

    day002 基础&运算符 1.循环语句 ### 1.循环格式 while 条件: print('') ''' while True: print('人生苦短,我用Python.') ''' ...

  2. SpringBoot 整合 slf4j 日志打印

    划水时间,记录一下用到的相关slf4j 日志打印,如何实现配置输出.本地保存log日志文件... 我使用的是SpringBoot框架,slf4j 类库已经包含到了 SpringBoot 框架中,所有, ...

  3. LCA(最近公共祖先)

    学习链接:https://baike.baidu.com/item/%E4%BC%B8%E5%B1%95%E6%A0%91/7003945?fr=aladdin 求LCA的方法有很多,在这里就只介绍一 ...

  4. linux下,matplotlib遇到的相关问题以及解决方法

    1.在linux下运行matplotlib程序时,matplotlib的安装. 根据不同的linux系统继续相关安装: Debian / Ubuntu : sudo apt-get install p ...

  5. logback.xml文件配置(按时间、文件大小和log名称生成日志)

    之前项目中日志多用的log4j2,偶然看到在importNew看到了logback,自己查了下,发现Logback和log4j是非常相似的,其作者也是同一个人,并且logback相比于log4j性能更 ...

  6. tar压缩命令

    01-.tar格式解包:[*******]$ tar xvf FileName.tar打包:[*******]$ tar cvf FileName.tar DirName(注:tar是打包,不是压缩! ...

  7. 解决display none到display block 渲染时间过长的问题,以及bootstrap模态框导致其他框中input不能获得焦点问题的解决

    在做定制页面的时候,遇到这么一个问题,因为弹出框用的是bootstrap的自带的弹出框,控制显示和隐藏也是用自带的属性控制 控制显示,在触发的地方 例如botton上面加上 data-toggle=& ...

  8. 【随笔】nginx重启问题和mysql挂了的解决办法

    租了一个阿里云服务器,然后需要一个nginx来处理一下静态文件的访问和动态文件的转发,头一天没有什么问题,第二次打开,各种问题就出来了!解决方法记录一下.... Can't connect to lo ...

  9. 【随笔】关于绝对定位absolute相对于父元素定位的问题

    绝对定位absolute的官方定义: 设置为绝对定位的元素框从文档流完全删除,并相对于其包含块定位,包含块可能是文档中的另一个元素或者是初始包含块.元素原先在正常文档流中所占的空间会关闭,就好像该元素 ...

  10. Swift编程权威指南第2版 读后收获

    自从参加工作一直在用OC做iOS开发.在2015年的时候苹果刚推出swift1.0不久,当时毕竟是新推出的语言,大家也都很有激情的学习.不过在学完后发现很难在实际项目中使用,再加上当时公司项目都是基于 ...