Effective C++ 读书笔记之Part5.Implementations

 26. Postpone variable definitions as long as possible.

总结:

尽可能延后变量定义式的出现。这样做可增加程序的清晰度并改善程序效率。

批注:

纯C语言此处有冲突,C语言要求变量定义出现在代码快的开始部分。

27. Minimize casting.

1)const_cast 通常被用来将对象的常量性转除(cast away the constness) 。它也是唯一有此能力的 C++-style 转型操作符。

2)dynamic_cast主要用来执行"安全向下转型"( safe downcasting) ,也就是用来决定某对象是否归属继承体系中的某个类型。它是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。

3)reinterpret_cast 意图执行低级转型,实际动作(及结果)可能取决于编译器,这也就表示它不可移植。例如将一个 pointer to int 转型为一个 int 。这一类转型在低级代码以外很少见。本书只使用一次,那是在讨论如何针对原始内存 (rawmemory) 写出一个调试用的分配器 (debugging allocator) 时,见条款50。

4)static_cast 用来强迫隐式转换 (implicit conversions) ,例如将 non-const对象转为 const 对象(就像条款3 所为) ,或将 int 转为 double 等等。它也可以用来执行上述多种转换的反向转换,例如将void*指针转为 typed 指针,将pointer-to-base 转为 pointer-to-derived。但它无挂将 const 转为 non-canst'一一这个只有const_cast 才办得到。

总结:

第一,如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_casts。如果有个设计需要转型动作,试着发展无需转型的替代设计。

第二,如果转型是必要的,试着将它隐藏于某个函数背后。客户随后可以调用该函数,而不需要将转型放进他们自己的代码内。

第三,宁可使用C++-style(新式)转型,不要使用旧式转型。前者很容易辨识出来,而且也比较有着分们别类的职掌。

28.Avoid returning "handles" to object internals.

总结:

避免返回handles(包括references、指针、迭代器)指向对象内部。遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生“虚吊号码牌”(dangling handles)的可能性将至最低。

批注:

虚吊号码牌应该指的就是指向的对象已经被销毁了,但是返回的指针或者引用还在使用。

29.Strive for exception-safe code.

当异常被抛出时。带有异常安全性的函数会:

1)不泄露任何资源。

2)不允许数据被毁坏。

异常安全函数(Exception-safe functions)提供以下三个保证之一:

1)基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效状态下。

2)强烈保证:如果异常被抛出,程序状态不改变。

3)包抛掷(nothrow)保证:承诺绝不抛出异常,因为他们总能完成它们原先承诺的功能。

copy and swap原则:为你打算修改的对象(原件)做出一份副本,然后在那副本身上做一切必要修改。若有任何修改动作抛出异常,原对象仍保持未改变状态。待所有改变都成功后,再将修改过的那个副本和原对象在一个不抛出异常的操作中置换(swap)。

总结:

第一,异常安全函数(Exception-safe functions)即使发生异常也不会泄漏资源或允许任何数据结构败坏。这样的函数区分为三种可能的保证:基本型、强烈型、不抛异常型。

第二,“强烈保证”往往能够以copy-and-swap实现出来,单“强烈保证”并非对所有函数都可实现或具备现实意义。

第三,函数提供的“异常安全保证”通常最高只等于其所调用哪个之各个函数的“异常安全保证”中的最弱者。

批注:

在现实程序的使用中,一般要求达到强烈型即可。因为基本型可能会导致一些不再使用的数据残留下来。而不抛异常型因为实现过于复杂的原因,一般也不达到这个级别。

30.Understand the ins and outs of inlining.

inline函数北周的整体观念是,将“对此函数的每一个调用”都以函数本体替换之。

inline函数通常一定被置于头文件内,大多数编译器会在编译期时候完成inlining,有些编译器会在链接期完成inlining,甚至有些编译器会在运行的时候完成inlining.

Templates通常也被置于头文件中,因为它一旦被使用,编译器为了将它具体化,需要知道它长什么样子。有些编译器会在链接期才执行template具体化,但是大多数情况下还是在编译器实现的具体化。

一个表面上看似inline的函数是否真是inline,取决于你的建置环境,主要取决于编译器。大多数的编译器提供了一个诊断级别:如果它们无法将你要求的函数inline化,会给你一个警告信息。

总结:

第一,将大多数inlining限制在小型、被频繁调用的函数身上。这可使日后的调试过程和二进制升级(binary upgradability)更容易,也可使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。

第二,不要只因为function templates出现在头文件,就将它们声明为inline。

批注:

templates和inline没有必然关系,需要加以区分。

31.Minimize compilation dependencies between files.

编译依存关系   compilication dependency

连串编译依存关系  cascading compilation dependencies

总结:

第一,支持“编译依存性最小化”的一般构思是:相依于声明式,不要相依于定义式。基于此构想的两个手段是Handle classes和Interface classes.

第二,程序库头文件应该以“完全且仅有声明式”(full and declaration-only forms)的形势存在。这种做法不论是否涉及templates都适用。

感悟:

这本书对于有一定的代码量的人会有很大的帮助,如果代码量不够的话,看起来会觉的很不好理解,也不容易记住这么多条款。当然,即使代码量够了,这本书也不是看一遍就可以扔了的,是属于可以放在案头不断的翻阅,直到这些条款的内容都融入骨髓。这部分的内容,我最大的感受就是很多东西在带来有利的一面的时候也带来了不利的一面,所以在使用的过程中要仔细的推敲,到底如何去用。没有哪种用法就一定万无一失,就一定会更好,要看具体使用的环境。

时间: 2024-10-30 05:25:13

Effective C++ 读书笔记之Part5.Implementations的相关文章

More Effective C++ 读书笔记五——异常

条款12:了解"抛出一个exception"与"传递一个参数"或"调用一个虚函数"之间的差异 第一,exception object总是会被复制,如果以by value方式捕捉,它们甚至被复制两次.至于传递给函数参数的对象不一定得复制.第二,"被抛出成为exceptions"的对象,其被允许的类型转换动作,比"被传递到函数去"的对象少.第三,catch子句以其"出现于源代码的顺序"被编译

More Effective C++ 读书笔记二

条款4:非必要不提供default constructor 这里主要是列举下默认构造函数的优点和缺点. 如果没有默认构造函数,定义对象数组会比较麻烦,因为对象数组初始化的时候没法传递非默认构造函数的值,如果要使用,书中提到的方法是给数组每个变量初始化的时候调用构造函数,另一个就是使用指针数组. 第一个的缺点很明显,没法声明类似A a[10];这样的数组,在堆上申请,还得用到placement new这个之前没讲过的东西,另外还得一个个去初始化:后者的缺点当然是,数组里面的每个指针都需要记得去de

Effective C++ 读书笔记之Part1.Accustoming Yourself to C++

1.View C++ as a federation of languages C++的四个次语言: 1)C 2)Object-Oriented C++ 3)Template C++ 4)STL 2.Prefer consts, enums, and inlines to #defines 一方面是因为使用宏定义不利于调试的时候定位错误,另一方面主要是因为预处理器和编译器两者分工不同所导致的. 同时,宏定义太复杂的情况下很容易出现错误. 总结: 第一,对于单纯常量,最好以const对象或enum

Effective C++ 读书笔记之Part6.Inheritance and Object-Oriented Design

32.Make sure public inheritance models "is-a". 所谓的最佳设计,取决于系统希望做什么事,包括现在与未来. 需要解决的问题:其中关于两个assert都通过的地方有些疑惑. 总结: "public继承"意味着is-a.适用于base classes身上的每一件事情一定也适用于derived classes身上,因为每一个derived class对象也都是一个base class对象. 33.Avoid hiding inh

More Effective C++ 读书笔记六——临时对象

条款19:了解临时对象的来源 c++真正的所谓的临时对象是不可见的--不会再你的源代码中出现.此等匿名对象通常发生于两种情况:一是当隐式类型转换(implicit type conveersions)被施行起来以求函数调用能够成功:二是当函数返回对象的时候. 第一种情况的例子: [cce lang="cpp"] #include <iostream> class Int { public: Int(int value) { _value = value; std::cout

More Effective C++ 读书笔记四——异常

条款9:利用destructors避免泄漏资源 这里开始介绍了auto_ptr,其实就是利用了c++局部对象在离开作用域的时候,其析构函数会被调用,来避免资源泄漏.这样的好处,就是不管是作用域正常结束(跑出代码块)还是异常结束(抛出异常),对象的析构函数都能保证被调用. 条款10:在constructors内阻止资源泄漏 c++只会析构已构造完成的对象.对象只有在其constructor执行完毕才算是完全构造妥当. 也就是说,c++不自动清理那些"构造期间抛出exceptions"的对

More Effective C++ 读书笔记三

条款8:了解各种不同意义的new和delete 这里讲了3种new,分别是:new operator, operator new, placement new. new operator最简单,它就是我们平时常用的new关键字,需要注意的是,它是不能被重载的.new operator的语义是先分配内存,然后调用对象的构造函数. operator new:这个是这三个new里面唯一能够重载的,平时我们重载的就是这个操作符.它的声明是: [cc lang="cpp"] void *oper

Effective C++ 读书笔记之Part2.Constructors, Destructors, and Assignment Operators

5.Know what functions C++ silently writes and calls. 总结:编译器可以暗自为class创建default构造函数.copy构造函数.copy assginment操作符,以及析构函数.这些函数都是public的,并且是inline的. 6.Explicitly disallow the use of compiler-generated functions you to not want. 总结:为驳回编译器自动(暗自)提供的机能,可将相应的成

Effective C++ 读书笔记之Part8.Customizing new and delete

49. Understand the behavior of the new-handler. 总结: 第一,set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用. 第二,Nothrow new是一个颇为局限的工具,因为它只适用于内存分配:后继的构造函数调用还是可能抛出异常. 50. Understand when it makes sense to replace new and delete. 替换编译器提供的operator new或operator dele