首页 > 代码库 > Effective c++关键点(一)

Effective c++关键点(一)


条款1:视C++为一个语言联邦


1.1 将C++视为一个由相关语言组成的联邦而非单一语言.
1.2 视C++由四块次语言组成:
C:区块,语句,预处理器,内置数据类型,数组,指针 等等来自于C语言的特性.
Object-Oriented C++:封装,继承,多态,virtual函数 等等面向对象特性.
Template C++:泛型编程.
STL:标准库.


条款2: 尽量以canst,enum,inline替换#define


2.1 宏定义的名称未登记在符号表,不易追踪编译错误.
2.2 宏定义没有封装性,无法随心控制作用域.
2.3 const 用法.
2.4 枚举类型 the enum hack.
2.5 用template inline函数代替宏定义函数.


条款3: 尽可能使用const


3.1 const 用法.
3.2 const出现在*星号左边,表示被指物是常量;
出现在*星号右边,表示指针自身是常量;
出现在*星号两边,表示被指物和指针两者都是常量.
3.3 STL选代器的const
const iterator: iterator is const,*iterator is non-const.
const_iterator: iterator is non-const,*iterator is const.
3.4 const可以修饰函数返回值、各参数、函数自身(如果是成员函数)。
3.5 bitwise canstness 成员函数只有在不更改对象之任何成员变量(static除外)时才可以说是const,也就是说它不更改对象内的任何一个bit。
logical constness 一个const成员函数可以修改它所处理的对象内的某些bits,但只有在客户端侦测不出的情况下才得如此。
3.6 const与mutable
在const成员函数内可修改mutable成员变量.
3.7 const类型转换
3.8 有实质等价功能的non-const和const函数间,non-const可以调用const函数,避免代码重复.const不可调用non-const函数.


条款4: 确定对象被使用前已先被初始化


4.1 有些类型有默认初始化,有些没有,所以永远在使用对象之前先将它初始化.
4.2 赋值与初始化:=等号是赋值操作,()括号是初始化操作. 
4.3 在构造函数内总是使用成员初值列初始化成员,而非赋值操作.
4.4 适当时候,将成员的初始化操作放在一个private函数内供构造函数调用.
4.5 成员初始化次序总是相同: 基类早于其子类被初始化,而类的成员变量总是以其声明次序被初始化,而不是以初始化列表中的排列顺序初始化.
4.6 C++对"定义于不同编译单元内的non-local static对象"的初始化次序并无明确定义。
4.7 以函数调用的的形式将non-static 对象转化为static对象.


条款5: 了解C++默认编写并调用哪些函数


5.1 没有构造函数的类,编译器默认声明
无参构造函数
copy构造函数
copy assignment操作符
析构函数.
5.2 手动编写任何一个构造函数后,编译器不再产生任何默认构造函数。
5.3 默认析构函数是non-virtual,仅在基类有virtual析构函数时才有。
5.4 内含reference成员、const成员的类内,编译器不会产生默认copy assignment操作符。
5.5 基类copy assignment操作符是private的话,编译器不会为子类产生默认copy assignment操作符。


条款6: 若不想使用编译器自动生成的函数,就该明确拒绝


6.1 通过将copy构造函数和copyassignment操作符声明为private,阻止编译器自动生成和用户调用.
6.2 可通过构造一个含有私有copy构造函数和copyassignment操作符的通用基类,子类继承时不必再声明private copy构造函数和copyassignment操作符即可阻止自动生成.


条款7: 为多态基类声明virtual析构函数


7.1 继承一个没有virtual析构函数的基类时,若子类对象被一个基类指针所指向,则在delete基类指针时,子类成分未被销毁。
7.2 基类的virtual析构函数保证在delete基类指针时,销毁指针实际所指向的对象,当然包括对象的基类对象.
7.3 通常,只有当类内含至少一个virtual函数,才为它声明virtual析构函数。
7.4 以多态为目的的基类通常含有virtual析构函数。
7.5 不要随便声明virtual析构函数,仅当明确需要时.
7.6 可以通过 纯虚析构函数 实现抽象基;纯虚析构函数需要在类外定义.


条款8: 不让异常逃离析构函数


8.1 会使析构函数终止,资源未完全释放.
8.2 通过try-catch在析构函数内捕获异常.
8.3 对于需要客户解决的异常,由另外单独一个函数实现这一可能异常的操作.


条款9: 绝不在构造和析构过程中调用virtual函数


9.1 构造和析构过程中调用的virtual函数是
9.2 非正式说法:在一个继承体系内,在基类构造函数执行期间,virtual函数不是virtual函数。


条款10: 令operator= 返回一个reference to *this


10.1 连锁赋值:x = y = z = 110;

条款11: 在operator= 中处理"自我赋值"


11.1 自我赋值安全性
11.2 异常安全性
11.3 copy and swap


条款12: 复制对象时勿忘其每一个成分


12.1 确保复制对象内所有成员变量
调用所有base classes 内的适当的copying 函数。
12.2 不要尝试以某个copying函数实现另一个copying函数。应该将共同的操作放进第三个函数中,并由两个coping 函数共同调用。


条款13: 以对象管理资源


13.1 资源取得时机便是初始化时机
13.2 单纯依赖一个单独的函数管理资源是行不通的。它可能会随时throw、return、continue、goto而跳过delete.
13.3 获得资源后立刻放进管理对象内
13.4 管理对象运用析构函数确保资源被释放
13.5 auto_ptrs智能指针:
若通过copy构造函数或copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权!
受auto ptrs 管理的资源必须绝对没有一个以上的auto-ptr同时指向它
13.6 shared_ptr引用计数型智能指针:无法打破环状引用


条款14: 在资源管理类中小心coping 行为


14.1 在一些资源管理类内禁止复制
14.2 使用类似shared_ptr的引用计数法
14.3 深度复制:连同其指针所指向内容一同复制。
14.4 auto_ptr:转移底部资源的拥有权


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


15.1 通过公用接口显示提供对原始资源的访问,比较安全.
15.2 通过隐式类型转换提供和对原始资源的访问对客户方便,但易被误用.
15.3 隐式类型转换.


条款16: 成对使用new和delete时要采取相同形式


16.1 如new 一个数组[]后,释放时,要以delete []形式释放.
16.2 小心对数组的重命名:typedef int intarray[4];


条款17: 以独立语句将new的对象放入智能指针


17.1 编译器不能改变一个程序内各个语句的执行顺序,但可以改变一个语句内,各个子句的执行顺序.
17.2 正是因为17.1,安全起见,以独立语句new一个对象.