`
hulianwang2014
  • 浏览: 690523 次
文章分类
社区版块
存档分类
最新评论
  • bcworld: 排版成这样,一点看的欲望都没有了
    jfinal

《Effective C++》读书笔记

 
阅读更多

第一章:让自己习惯C++

1、视C++为一个语言联邦

a、C++由四个部分组成: C、Object-Oriented C++、Template C++、 STL。

b、每一个部分有自己独立的高效编程守则

2、用const、enum、inline代替#define

a、#define是预处理器处理的部分,当编译出错时,不容易发现错误发生在哪里,其次由于预处理器盲目的替换,会导致目标码的增大

b、定义常量指针时采用如下两种方法: const char* const ptr = ”hello world“、const std::string ptr(”hello world“)

c、#define并不重视作用域,所以无法定义class中常量变量

d、对于类中常量,某些编译器不允许声明时进行初值设定,而类其他成员依赖这个常量,可以采用enum来实现

e、用inline来代替形似函数的宏

3、尽可能的使用const

a、char* const ptr、const char* ptr、char const *ptr、和const char* const ptr的含义

b、const成员函数的作用:使接口容易被理解、消除误操作的隐患、使操作const对象成为可能

c、两个成员函数如果只有常量性不同,可以被重载。

d、当const与non-const发生重复时,可以使用non-const版本调用const(使用const_cast和static_cast)

4、确定对象使用前已经初始化

a、为内置型对象进行手工初始化,因为C++不保证初始化它们;

b、构造函数最好使用成员初值列,而不是在构造函数本体内进行复制操作,初值列列出的成员变量,其排列顺序应该跟声明相同

c、以local static对象代替non-local static对象;

第二章:构造/析构/赋值运算

5、了解C++默默地编写了并调用哪些函数

a、default构造函数,复制构造函数,赋值操作符,析构函数;

b、如果是一个独立的类,上面的函数默认为public,如果是一个派生类,上面的函数与基类保持一致

c、如果类里面有引用变量,则default构造函数,赋值操作符都无效;

6、若不想编译器自动生成函数,就应该明确的拒绝

a、因为默认的上述四个函数都是public,我们可以只显示的声明他们,而不去实现他们,并且将它们定义为private; 不实现他们是因为成员函数和友元函数可以访问private;如果不实现他们,而在成员函数或友元函数调用它的时候,就会提示连接错误

b、还有一种方式就是定义一个上述这样的基类,然后不干其他的事,如果你需要其他的类来拒绝默认函数,就直接继承这个基类就可以了

7、为多态基类声明虚析构函数

a、我们知道,虚函数的作用主要体现在当用表面上是基类指针,实际上市指向派生类对象进行操作的时候,在这种情况下,当我们销毁对象时,如果不是虚函数,就会造成基类部分被释放,派生类部分不被释放的局部销毁情况。

b、带有多态性质的基类应该声明虚析构函数;如果一个类中有一个以上的虚函数,则应该声明虚析构函数。

c、类不是作为基类用,或不具备多态性,就不应该声明虚析构函数。

8、别让异常逃离析构函数

a、析构函数绝对不要吐出异常,如果一个析构函数调用的函数可能会抛出异常,那么析构函数应该吞掉它们(不传播)或是结束程序

b、如果客服需要对某个操作函数运行期间可能抛出的异常做反应,那么class应该提供一个普通的成员函数(而不是在析构函数中)执行该操作。

9、绝不在构造和析构函数中调用虚函数

a、简单的理解就是基类的构造函数在调用时派生类还没有创建,所以试图实现这种多态是不可能的,对于析构函数一样,因为派生类对象已经销毁。

10、令operator=返回一个reference *this

a、与内置内型和标准库共同遵守

11、在operator=中处理自我赋值

a、确保对象在进行自我赋值时operator=有良好的行为,具体的方法有比较来源和目标的地址,正确的语句顺序、copy-and-swap

b、确定一个函数在操作多个对象是,而多个对象实际上是同一个对象,其行为仍然正确。

12、复制对象时勿忘复制每一个成分

a、编译器会提供默认的copy构造函数和copy assignment操作符。如果我们认为默认的copy函数无法满足我们要求时,我们必须重写这两个函数,在重写这两个函数时,对于对象里面每个成分都要显示的进行复制

b、在有继承关系的类中,对于自己写的赋值构造函数,如果在派生类构造函数中只对派生类成员进行了复制的话,会导致部分复制的错误,因为这个时候派生来不会调用基类的复制构造函数进行构造,而是会调用无参数的构造函数进行构造,这样基类的成员就没有复制下来,所以在派生类中要显示的加上基类的复制构造函数。

c、不要尝试一个copying函数调用另一个copying函数,因为我们无法知道在copying函数幕后到底工作了什么,而是可以将共同的部分交由第三个函数,然后copying函数共同调用这个函数

第三章:资源管理

13、以对象管理资源

a、当我们在一个函数开始时候new出来一个类对象,在函数结束时delete这个对象,并不是总能释放掉这块资源,因为在new和delete之间可以有return和goto等控制语句,导致执行不到delete,还有就是当中间有异常发生时,正常的控制流被终止,也不会执行到delete,这样就导致了资源的泄露

b、为防止资源泄露,应该使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源

c、两个常用的RAII class分别是trl::shared_ptr和auto_ptr,注意两者的区别

14、在资源管理类中小心copying行为

a、复制RAII对象必须一并复制它所管理的资源,并以资源的copying行为决定RAII对象的copying行为

b、普通而常见的RAII class copying行为有:抑制copying、引用计数法。

15、在资源管理类中提供对原始资源的访问

a、API往往要求访问原始资源,所以每一个RAII class应该提供一个“取得其所管理的资源”的方法

b、对原始资源的访问有两种方式,显示和隐示。

16、成对使用new和delete要采用相同的形式

a、如果你在new表达式的时候采用了[],必须在相应的delete表达式加上[];如果你在new表达式的时候没有采用[],在在相应的delete表达式一定不要加上[]

b、如下代码: typedef T A[4]; T* pA = new A; 则要使用delete[];因为new A 返回一个T*指针,就像new T[4]一样。注:T表示一个对象

17、以独立语句将newed对象置入智能指针中

a、以独立语句将newed对象置入智能指针中,如果不这么做,一旦异常被抛出,可能导致难以察觉的资源泄露。

第四章:设计与声明

18、让接口容易正确使用,不易被勿用

a、好的接口应该容易使用,不易被勿用,在设计接口时应该努力达到这点

b、要保持接口的一致性,以及与内置类型的行为相同

c、阻止勿用的措施有建立新类型,限制类型上的操作,束缚对象值以及消除客户的资源管理责任

d、trl::shared_ptr支持定制性删除器

19、设计class应该考虑的问题

a、class如何被创建和销毁 ------------------- 构造函数和析构函数的写法,以及new delete操作符的运用相关问题

b、对象的初始化和对象的赋值之间的差别---------构造函数和赋值操作符的行为,以及成员初始化列表相关问题

c、对象以pass-by-value意味着什么-------------copy构造函数的实现、用来作为pass-by-value之用

d、新类的合法值-------------------------------错误检查机制

e、是否配后某个集成类图-----------------------是否为基类或是子类或不包含继承关系的类

f、新类需要什么样的转换-----------------------是否需要类型转换函数

g、什么样的操作符和函数对该类是合理的--------成员函数的依据

h、什么样的函数调用应该驳回------------------申明为private类型的依据

i、新类的成员属性-----------------------------成员变量的public、private、和protect属性

j、新类的一般性-------------------------------考虑是否写成模板类

20、用pass-by-reference-to-const替换pass-by-value

a、默认情况下,C++采用pass-by-value来进行函数参数的传递

b、pass-by-value由于有对象的赋值以及构造函数、析构函数的调用,会造成内存的增大,效率的下降,同时在将派生类作为基类函数参数传递时,会造成派生类数据截断

c、对于内置类型、STL迭代器和函数对象,一般采用pass-by-value

21、必须返回对象时,别妄想返回reference

a、如果在函数内定义对象,即在stack上创建对象,然后再返回改对象的引用,这样可以避免返回参数时候的构造开销,但问题是随着函数的执行完成,对象的生命周期结束,对象也就自动销毁了,返回的引用也就指向了一个销毁了的对象,会产生不明确行为。

b、如果在heap上创建对象,返回指针,这样一种策略会导致new 和delete分属不同的使用者,极容易导致内存泄露

c、定义静态对象,返回引用,这样一种策略也会导致隐患。比如说一个重载乘法的操作符,当执行下面语句时if(a*b == c*d)就会产生不符合预期的效果。其实对于多线程也会产生不符合预期的结果

d、采用返回对象的方式会有对象构造的开销,但相对于上述的不安全行为,这样一种开销是值得的。

22、将成员变量申明为private

a、可以对每个变量进行读写控制

b、获得更加的封装性,比如你对一个public成员变量进行改变时,会影响到所用使用该类的客服端代码,对于protect成员变量,会影响到所有派生类代码

23、以non-member-non-friend函数代替member函数

a、提供封装性,因为采用这种方式可以减少对类private成分的访问函数,从而更有利于封装

b、通过使用namespace可以降低编译依赖以及功能进行扩充

24、若所有参数皆需要类型转换,请为此采用non-member函数

a、只有当参数被列为参数列时,才有可能执行隐示类型转换

25、不抛出异常的swap函数

第五章:实现

26、尽量延后变量定义式的出现时间

a、如果一个对象过早的定义,而中途或是因为异常或是由于控制语句导致这个对象没有用到,这就会无缘无故的增大了开销

b、不仅要延后到确实需要使用对象,更要延后到对象具有初值时,这样可以避免调用default构造函数的开销。

c、同时这样还可以增加程序的可读性。

27、尽量少做转型动作

a、C++提供的四种新式转型:const_cast<T>(epr)、dynamic_cast<T>(epr)、static_cast<t>(epr)、reinterpret_cast<T>(epr)

b、尽可能的用C++类型转换,在注重效率的代码中避免使用dynamic_cast,如果一定需要,可以设计一个无转型的方案

c、尽量避免转型

28、避免返回Handle指向对象的内部成分

a、注意return-by-reference、return-by-reference-to-const的问题

b、可以尽量防止Handle管理一个空对象

30、详解Inline

a、编译器会对Inline函数进行最优化

b、 目标码和函数调用效率的问题

c、将小型、频繁调用的函数声明为Inline

31、将文件间的编译依存关系尽可能的降到最低

a、相依与声明式,而不是定义式,有两种方法:Handle class 和Interface class

b、程序库头文件应该以“完全声明式”的形式存在

第六章:继承与面向对象设计

32、确保public继承是is-a关系

a、“public 继承”应该是is-a关系,适用于base class的每一件事应该同样适用derived class,因为每一个derived class对象也是一个base class对象

33、避免遮掩继承而来的名称

a、编译器对变量名称的匹配是由内向外,一旦找出就停收索,然后再检查变量类型是否匹配正确

b、derived class内的名称会遮掩base class内的名称,在public继承的情况下就不可能满足is-a的关系了

c、为了让base class中被遮掩的名称起作用,可以采用using class或转交函数

34、区分接口继承和实现继承

a、pure-virtual只指定接口继承

b、impure-virtual指定接口继承和缺省的实现继承

c、non-virtual指定接口继承和强制性的实现继承

35、考虑virtual函数以外的选择

a、NVI手法实现Template-Method模式,优势在于可以做一些virtual函数调用之前和之后的处理,这时候重写virtual函数的意义在于某事如果被完成,而重写常态写的virtual函数表示某事何时被完成

b、用Function Pointer实现stragegy模式,优势在于即使同一类型对象也可以有不同的处理方法,缺陷在于降低了封装性。

c、由trl::function实现stragegy模式,优势在于可以提供一个泛化的调用对象。

36、绝不重新定义继承而来的non-virtual函数

a、non-virtual是静态绑定的,如果重新定义,打断了is-a的关系

37、绝不重新定义继承而来的的缺省参数值

a、所针对的是virtual函数,对于non-virtual函数不应该重新定义

b、virtual函数是动态绑定,而缺省参数值是静态绑定,

c、编译器会产生以下怪异现象:

class A{ virtual int Get(int a=1){ return a;}};

class B:public A { virtual int Get(int a=2){ return a+4;}};

A *p =new B; int c = p->Get();

会得到c=5;这是因为编译器会调用B::Get(int a= 1);

d、如果虚函数确实需要带缺省参数,base class 和derived class都要声明该借口,会导致代码重复,一旦更改也很麻烦,增加了维护的难度,解决方法可以采用NVI手法进行

38、通过复合实现“has-a”或“is-implemented-in-term-of”

a、“has-a”表示复合的对象都是其复合的一部分,也就是要用到里面的相关数据,而“is-implemented-in-term-of”并不是获得其相关数据,而是用到它的相关方法来对数据进行快捷处理。

39、使用private继承

a、private意味着“is-implemented-in-term-of”,它在软件设计层面无意义,而在软件实现层面有意义。

b、和复合一样,那什么时候使用复合,什么时候使用private继承呢,通常情况下,使用复合来实现,只有当protected成员或virtual函数牵扯进来时使用private继承

c、private继承可以造成empty base最优化

40、明智的使用多重继承

a、会造成歧义,如两个base class 有相同的函数名

b、对于环状继承而言,会生成两份base class对象,除非采用virtual继承。

c、virtual继承会增加大小,速度、初始化复杂度成本

d、多重继承有它自己的使用情形,其中之一就是“以public继承某个 interface class”和“以private继承某个协助实现的class”的两相组合。

第七章:模板和泛型编程

41、了解隐式调用接口和编译器多态

a、面向对象编程总是以显示接口和运行期多态解决问题,而泛型编程更多的是隐式接口和编译期多态

b、显示接口以函数签名式为中心,运行期多态通过virtual实现,隐式接口以有效表达式为中心,编译期多态通过template具体化和函数重载解析实现

42、typename的双重意义

a、声明template参数时,class和typename可以互换

b、编译器遇到嵌套从属名称时,会假设它不是一个类型,

b、要使用typename表示嵌套从属类型名称,但不能再base class list或member initalization list中使用typename。

43、学会处理模板化基类内的名称

a、因为存在模板特化,所以在derived class直接调用成员函数,就可能不能通过编译,因为编译器无法获知基类中是否一定有这样一个函数存在。

b、有三个解决方法:一是在base-member-function前加上this->,第二一个是使用using声明,告诉编译器假设有这样一个函数存在,第三一个是使用作用域限定符告诉编译器这个函数将被继承下来

44、将与参数无关的代码抽离template

分享到:
评论

相关推荐

    effective c++读书笔记

    effective c++读书笔记和总结 effective c++读书笔记和总结

    effective C++读书笔记

    effective C++读书笔记,effective C++读书笔记,effective C++读书笔记

    effective C++ 读书笔记

    effective C++ 很好 很不错 最好的C++进阶资料

    effective C++ 读书笔记 PPT

    摘录了《Effective C++》 (Scott Meyers 著)中有参考价值的编写代码建议,方面阅读

    Effective C++学习笔记

    Effective C++学习笔记 没有时间看Effictive C++书的人可以看看这个笔记 总结出了重点啊 适合有c++基础的人阅读

    Effective Modern C++学习笔记

    《Effective Modern C++:改善C++11和C++14的42个具体做法(影印版)(英文版)》中包括以下主题:剖析花括号初始化、noexcept规范、完美转发、智能指针make函数的优缺点;讲解std∷move,std∷forward,rvalue引用和全局...

    Effective C++学习笔记.doc

    自己整理的侯捷版本&lt;&lt;Effective C++ 改善程序与设计的55个具体做法&gt;&gt; 学习笔记.

    Effective C++第三版及详细笔记

    内容简介:有人说C++程序员可以分为两类,读过Effective C++的和没读过的。当您读过《Effective C++:改善程序与设计的55个具体做法(第3版)(中文版)(双色)》之后,就获得了迅速提升自己C++功力的一个契机。

    effective c++笔记1

    effective c++笔记1

    Effective C++笔记1

    Effective C++笔记1

    Effective C++ Roy T 读书笔记。

    Effective C++ Roy T 读书笔记,比较老的一本书,探讨一下C++。

    Effective_C++_3rd笔记.pdf

    Effective_C++_3rd 读书笔记 pdf

    effective C++ (3rd) 学习笔记

    经典书籍 effective c++的学习笔记,一共31页,总结的很好,基本上是把原书的精华内容再加上自己的理解写在了这份文档中,适合打印出来细看。

    Effective_C++_笔记

    通常C++要求你对所使用的任何东西提供一个定义式,但如果它是个class专属常量 又是static且为整数类型(integral type,例如int,char,bool),则可特殊处理。只要不取它们 的地址,你可以声明并使用它们而无需提供...

    C++Effective STL笔记

    C++ Effective STL笔记,供C++初学者学习参考。。。。。

    C++书籍阅读笔记

    深入探索C++对象模型,Effective STL,more effective c++,C陷阱与缺陷,都是阅读笔记

    Effective C++中文版

    Effective C++_中文版. 数据C++中的高级进阶类书籍,本文档可以复制,非影印版

    c++笔记学习心得笔记

    c++笔记学习心得笔记,年多的C++学习过程中,自己阅读了很多C++经典著作,有《effective c++》,《more effective c++》,《c++ primer》等,每次阅读著作都会总结一些心得,现在拿出来和大家分享一下。

Global site tag (gtag.js) - Google Analytics