这事篇读书笔记,只记录自己的理解和总结,一般情况不对其举例子具体说明,因为那正是书本身做的事情,我的笔记作为梳理和复习之用,划重点。我推荐学C++的人都好好读一遍Effective C++ 系列,真是好书啊,对于学完C++ 基础知识的人,这是本高阶秘籍。

笔记

条款 9 - 15 关注的主题是异常。关注1、异常可能引起的资源泄露(强烈推荐使用智能指针)2、异常是如何抛出的和3、异常的成本。目的是写出 exception-safe 的程序。

  • 条款9: 利用 destructor避免资源泄露

    这个条款是说如果异常被抛出到调用端,但是调用端没有catch, 如果调用端是指针,用来析构指针的delete语句可能因为异常被抛出而跳过,导致资源泄露。最好的办法就是不用指针,用临时对象,或者说用行为类似指针的临时对象(为什么非要用类似指针的行为呢?为了多态),临时对象会在对象生存期结束的时候析构,在析构函数中delete(如果有指针的话) 释放资源。这里的原则就是所谓RAII(Resource Acquisition Is Initialization),在具体实践上就是使用智能指针,C++11 中提供了std::shared_ptr 和 std::unique_ptr,目的就是为了避免资源泄露。

  • 条款10:在 constructor 内阻止资源泄露。 这个条款举例子说明了如果在对象构造时发生了异常,这个时候因为构造未完成故不会调用该对象的析构函数,该对象的指针成员面临着没有delete 的风险,导致资源泄露。解决办法跟条款9一样,想用指针的时候使用智能指针。

  • 条款11:禁止异常流出destructors 之外。 这个条款是要说明,如果异常发生在destuctor中,不要将其抛出。 理由1是因为如果这个destuctor是因为某个异常而调用的,在这时候再次发生异常并抛出会导致程序 terminate,程序将会终结,也就是最不喜欢看到的程序崩了。处理方式是把异常给吞了,如下面的例子。理由2是如果异常被抛出,引起异常的函数后面的代码都没有被执行,析构函数没有析构完。因此要尽力阻止异常被destrucor 抛出。

~AClass(){
try{
a_function_may_throw_exception();
}catch(...){
// done nothing.
}
}
  • 条款12:了解“抛出一个异常excption” 与“传递一个参数”或者“调用一个虚函数”之间的差异。 首先得明确一点, 抛出异常,事实上也是抛出异常对象,看上去跟传递对象参数是很类似的。(1) 但是,异常在抛出的时候总是伴随着对象copy行为(想想这是为什么,提示与局部对象生存期有关),也因此在效率上发生折扣。常见参数的传递的方式有 by value, by reference, by pointer. 不管是 by value 还是 by reference 抛出异常实例都会引起复制,捕捉异常时 by value 还要多复制一次。 throw by pointer 和 pass by pointer。 都是传递指针的副本,千万不要传递一个指向局部对象的指针,否则会获得一个指向已销毁的对象的指针。(2) 传递exception 不会发生隐式类型转化,除非是有型指针转为 void* 或者是继承架构中的转化(catch base 的可以catch derived 的异常),catch 语句中遵循 first fit, 即第一个匹配的就被捕捉,所以 base exception 会拦截 derived excetion。(因此应该让catch derived excaption 的语句放在前面)。
  • 条款13:以 by reference 的方式捕捉异常。 无论如何不要用 by pointer 方式捕捉异常; by value 传递会有slice 问题而且比 by reference 多复制一次。综合条款 12 和13 ,结论就是使用 by reference 的方式捕捉异常。
  • 条款14:明智运用exception specifications。 这是一把双刃剑,一方面对于函数希望提供什么样的exception 提供了说明,另外也带来了不安全的行为。unexcepted 函数默认终结程序,如果违反了 exception specification 会调用unexception函数。记住1.不要和模板 template 混用;2.不要对回调函数使用exception specification.

Note:

  1. void foo() throw(); // 含义是不抛出异常
  2. void foo() throw(A,B,C); // 含义是可能抛出A,B,C 型异常
  3. 书中76 页中介绍了 set_unexpected()函数和将非预期的异常转化为已知异常的技术,可以较为安全的处理unexpected 发生。
  • 条款15:了解异常处理(excption handling)的成本。 成本主要是三点:1.为了支持异常,程序需要做大量簿记工作,消耗额外的内存和时间,而且因为只要程序库或者用户代码任何一处用了异常处理,编译器就必须提供对异常处理的支持能力。 2. 编译器实现try语句块和 excpetion specification 带来的代码膨胀和性能损失,2000年之前作者写这本书的时候,得到的消息和测试结果是 5%-10%的损失,不知道现在谁否有提升。 3.抛出异常的损失,可能比正常的函数返回要慢三个数量级。注意,这个只是在发生异常并抛出的时候才有,而异常应该是比较少发生才是。

总结

  1. 为了异常安全,使用智能指针;
  2. 析构函数不要抛出异常,应该吞掉;
  3. 捕捉catch 异常应该 by reference;
  4. 异常处理是有成本的。(迷思:这些成本如今是否得到优化,或者项目可以容忍?如果我开始一个新项目,我要不要使用异常处理?)

《More Effective C++ 》读书笔记(二)Exception 异常的更多相关文章

  1. Effective STL 读书笔记

    Effective STL 读书笔记 标签(空格分隔): 未分类 慎重选择容器类型 标准STL序列容器: vector.string.deque和list(双向列表). 标准STL管理容器: set. ...

  2. Effective STL读书笔记

    Effective STL 读书笔记 本篇文字用于总结在阅读<Effective STL>时的笔记心得,只记录书上描写的,但自己尚未熟练掌握的知识点,不记录通用.常识类的知识点. STL按 ...

  3. 《你必须知道的.NET》读书笔记二:小OO有大原则

    此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.单一职责原则 (1)核心思想:一个类最好只做一件事,只有一个引起它变化的原因 (2)常用模式:Fa ...

  4. spring揭秘 读书笔记 二 BeanFactory的对象注册与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Pr ...

  5. how tomcat works 读书笔记(二)----------一个简单的servlet容器

    app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...

  6. ES6读书笔记(二)

    前言 前段时间整理了ES6的读书笔记:<ES6读书笔记(一)>,现在为第二篇,本篇内容包括: 一.数组扩展 二.对象扩展 三.函数扩展 四.Set和Map数据结构 五.Reflect 本文 ...

  7. effective c++读书笔记(一)

    很早之前就听过这本书,找工作之前读一读.看了几页,个人感觉实在是生涩难懂,非常不符合中国人的思维方式.之前也有博主做过笔记,我来补充一些自己的理解. 我看有人记了笔记,还不错:http://www.3 ...

  8. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

  9. spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...

  10. 【记】《.net之美》之读书笔记(二) C#中的泛型

    前言 上一篇读书笔记,很多小伙伴说这本书很不错,所以趁着国庆假期,继续我的读书之旅,来跟随书中作者一起温习并掌握第二章的内容吧. 一.理解泛型 1.为什么要使用泛型?-----通过使用泛型,可以极大地 ...

随机推荐

  1. 解决apache启动错误:Could not reliably determine the server's fully qualified domain name

    启动apache遇到错误:httpd: Could not reliably determine the server's fully qualified domain name [root@serv ...

  2. Spring Cloud Sleuth 之Greenwich版本全攻略

    微服务架构是一个分布式架构,微服务系统按业务划分服务单元,一个微服务系统往往有很多个服务单元.由于服务单元数量众多,业务的复杂性较高,如果出现了错误和异常,很难去定位.主要体现在一个请求可能需要调用很 ...

  3. CUDA 版本,显卡驱动,Ubuntu版本,GCC版本之间的对应关系

  4. java获取服务器基本信息

    实现步骤: (1)创建servlet BrowserServer (2)调用HttpServletRequest对象的getServerName()方法获取服务器名称 (3)调用HttpServlet ...

  5. shell习题第9题:sed的常用用法

    [题目要求] 把一个文本文档的前5行中包含字母的行删除掉,同时把6到10行中的全部字母删除掉. [核心要点] sed命令 [脚本] .txt |sed '/[a-zA-Z]/d' .txt |sed ...

  6. 解决docker pull出现 error pulling image configuration: Get https://dseasb33srnrn.cloudfront.net······: net/http: TLS handshake timeout的问题

    [root@MyCentos7 var]# docker pull javaUsing default tag: latestTrying to pull repository docker.io/l ...

  7. Java Hibernate Validator

    Hibernate Validator是Hibernate提供的一个开源框架,使用注解方式非常方便的实现服务端的数据校验. 官网:http://hibernate.org/validator/ hib ...

  8. Rabbitmq(一)

              ClientA,ClientB: 为Producer,数据的发送方. Client1,Client2,Client3:为Consumer,数据的接收方. Exchange:消息交换 ...

  9. daterangepicker的个性化使用技巧

    由于该模板不自动将时间戳添加到input中去,始终为NaN,所以,自己选取起始时间与截止时间 var startTime =new Date(new Date().toLocaleDateString ...

  10. Python-type函数使用