《More Effective C++ 》读书笔记(二)Exception 异常
这事篇读书笔记,只记录自己的理解和总结,一般情况不对其举例子具体说明,因为那正是书本身做的事情,我的笔记作为梳理和复习之用,划重点。我推荐学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:
void foo() throw(); // 含义是不抛出异常void foo() throw(A,B,C); // 含义是可能抛出A,B,C 型异常- 书中76 页中介绍了 set_unexpected()函数和将非预期的异常转化为已知异常的技术,可以较为安全的处理unexpected 发生。
- 条款15:了解异常处理(excption handling)的成本。 成本主要是三点:1.为了支持异常,程序需要做大量簿记工作,消耗额外的内存和时间,而且因为只要程序库或者用户代码任何一处用了异常处理,编译器就必须提供对异常处理的支持能力。 2. 编译器实现try语句块和 excpetion specification 带来的代码膨胀和性能损失,2000年之前作者写这本书的时候,得到的消息和测试结果是 5%-10%的损失,不知道现在谁否有提升。 3.抛出异常的损失,可能比正常的函数返回要慢三个数量级。注意,这个只是在发生异常并抛出的时候才有,而异常应该是比较少发生才是。
总结
- 为了异常安全,使用智能指针;
- 析构函数不要抛出异常,应该吞掉;
- 捕捉catch 异常应该 by reference;
- 异常处理是有成本的。(迷思:这些成本如今是否得到优化,或者项目可以容忍?如果我开始一个新项目,我要不要使用异常处理?)
《More Effective C++ 》读书笔记(二)Exception 异常的更多相关文章
- Effective STL 读书笔记
Effective STL 读书笔记 标签(空格分隔): 未分类 慎重选择容器类型 标准STL序列容器: vector.string.deque和list(双向列表). 标准STL管理容器: set. ...
- Effective STL读书笔记
Effective STL 读书笔记 本篇文字用于总结在阅读<Effective STL>时的笔记心得,只记录书上描写的,但自己尚未熟练掌握的知识点,不记录通用.常识类的知识点. STL按 ...
- 《你必须知道的.NET》读书笔记二:小OO有大原则
此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.单一职责原则 (1)核心思想:一个类最好只做一件事,只有一个引起它变化的原因 (2)常用模式:Fa ...
- spring揭秘 读书笔记 二 BeanFactory的对象注册与依赖绑定
本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Pr ...
- how tomcat works 读书笔记(二)----------一个简单的servlet容器
app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...
- ES6读书笔记(二)
前言 前段时间整理了ES6的读书笔记:<ES6读书笔记(一)>,现在为第二篇,本篇内容包括: 一.数组扩展 二.对象扩展 三.函数扩展 四.Set和Map数据结构 五.Reflect 本文 ...
- effective c++读书笔记(一)
很早之前就听过这本书,找工作之前读一读.看了几页,个人感觉实在是生涩难懂,非常不符合中国人的思维方式.之前也有博主做过笔记,我来补充一些自己的理解. 我看有人记了笔记,还不错:http://www.3 ...
- Effective Java读书笔记完结啦
Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...
- spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定
本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...
- 【记】《.net之美》之读书笔记(二) C#中的泛型
前言 上一篇读书笔记,很多小伙伴说这本书很不错,所以趁着国庆假期,继续我的读书之旅,来跟随书中作者一起温习并掌握第二章的内容吧. 一.理解泛型 1.为什么要使用泛型?-----通过使用泛型,可以极大地 ...
随机推荐
- 学习一份百度的JavaScript编码规范
JavaScript编码规范 1 前言 2 代码风格 2.1 文件 2.2 结构 2.2.1 缩进 2.2.2 空格 2.2.3 换行 2.2.4 语句 2.3 命名 2.4 注释 2.4.1 单行注 ...
- GraphQuery - Powerful html/xml query language
GraphQuery GraphQuery is a query language and execution engine tied to any backend service. It is ba ...
- 记一次 oracle 12.2 RAC : Transaction recovery: lock conflict caught and ignored
节点一 alert日志: PDB(17):Transaction recovery: lock conflict caught and ignored PDB(17):Transaction reco ...
- iOS 使约束带动画效果(Animate NSLayoutconstraints)
http://stackoverflow.com/questions/12926566/are-nslayoutconstraints-animatable http://stackoverflow. ...
- 纯 js 实现上传文件支持拖拽
开发「bufpay.com 个人即时到账收款平台」 后台需要支持开发者的微信和支付宝二维码上传. <p> <button class="btn btn-primary&qu ...
- 关于javascript中call()和apply()方法的总结
前段时间在使用javascript的过程中遇到了继承的问题,自己顺便就对call()和apply()方法进行了了解. 两个方法的共同之处:这两个方法作用相同,都用来改变当前函数调用的对象,即改变thi ...
- 可编辑div中包含子元素时获取光标位置不准确的问题
前言: 高亮显示输入框中的关键字符,这就必须得用到可编辑div(或其他标签)元素了,这时我们需要获取光标的位置,以便插入字符. 正文: 正常情况下获取光标位置,代码如下: function getPo ...
- 数据立方体(Cube)
如上图所示,这是由三个维度构成的一个OLAP立方体,立方体中包含了满足条件的cell(子立方块)值,这些cell里面包含了要分析的数据,称之为度量值.显而易见,一组三维坐标唯一确定了一个子立方. 多位 ...
- homebrew 使用心得
''' 安装anaconda 安装命令: brew search anaconda brew cask install anaconda 添加环境变量: vi ~/.bash_profile expo ...
- Git 命令及使用经验
手册中的基本命令: CONFIGURE TOOLING Configure user information for all local repositories $ git config --glo ...