第一章 从 C 到 C++
条款1 C++是语言联邦
这条意思是C++支持面向过程、面向对象、泛型编程、函数编程、元编程五中编程方式,但是会令人困惑。所以他是一门综合语言。条款2 const enum inline 代替 define
define不是语言的一部分,而是预处理的部分。const enum inline可以被编译器发现错误条款3 使用const来限制出错的可能
例如返回const引用对象来防止用户修改。使用const成员函数来防止对类的破坏。条款4 使用对象前确保已经初始化
主要是使用参数初始化列表初始化成员或者父类。另外如果类使用了全局的对象,则无法知道什么时候初始化的这个对象。所以需要使用类内部的static变量。(也是只有一份)
第二章 有关对象的构造与析构
- 条款5 了解对象的默认成员函数
编译器会根据需要的时候,默认生成的成员函数包括默认构造函数,拷贝构造函数,析构函数,拷贝赋值函数。
其中,默认拷贝赋值函数会可能无法拷贝引用成员。
条款6 使用=delete来拒绝默认生成的成员函数
这个可以防止类被拷贝,组织拷贝条款7 为多态基类声明virtual析构函数
这个是基本功了。条款8 析构函数不要抛出异常
这个可能导致内存释放不完全,或者导致抛出多个异常条款9 构造函数和析构函数中中不调用虚函数
这条也比较明显,派生类的构造函数如果进入到基类构造函数中,调用了虚函数,此时派生类的虚函数还没有准备好。条款10 operator = 应该返回对象的引用
这样就可以连续赋值了条款11 在operator = 处理自我赋值
很难保证你的自我赋值代码没有问题,而且自我赋值是浪费时间的行为。条款12 复制对象时记得复制每一个部分
这个很显然了。你要实现赋值函数,那么就必须拷贝所有内容。
第三章 有关对象的持有资源
条款13 对象是持有资源的基本单位
要能够获取资源,还要能够正确释放资源。关键在于使用shared_ptr来管理内存。可以自动释放持有的资源条款14 持有资源的对象复制
要么禁止复制,要么使用shared_ptr成员,要么进行深度拷贝,要么使拷贝过程变为资源的转移。条款15 持有资源的对象需要提供一个原始对象的方法
这个世界并不完美,许多APIs需要传递原始资源的指针才可以。使用shared_ptr会干扰这个对象的使用方式条款16 new数组对象的时候需要delete
为了避免这种错误,可以使用vector容器来进行操作,避免对new数组的需求条款17 new对象作为参数传入式可能导致内存泄漏
假如new对象和参数传入shared_ptr中间抛出了异常,那么就会导致内存泄漏
第四章 设计与声明
条款18 让接口容易被正确使用
接口有的时候难以表述清楚,比如传入三个int值,你得清楚的记得这三个值每一个到底是什么。如果传入的参数反了怎么办?这里书上提到了传入特定对象以及使用explicit来限定参数。其实也可以构建一个日期对象,然后指定成员,我感觉这种还好一点。另外,接口除了参数要设置的合理,返回值也要设置的合理(比如返回智能指针而不是原始指针强迫对方)。条款19 设计class是个大工程
对象的创建、销毁,对象初始化与对象赋值,对象通过值拷贝传递会异常吗,新type的合法值是什么。类型转换函数写了吗。operator呢。哪些函数应该被delete?条款20 传递常量引用代替传值
传值会带来对象的构造函数的调用,消耗时间,传递引用就是传递指针条款21 返回临时对象时无法返回对临时对象的引用
如果返回一个由函数创建的对象时,无法返回对该对象的引用。编译器会自己做出正确的优化步骤。条款22 成员变量应该声明为private
如果声明为public,那么删除这个变量会导致所有程序重写。如果声明为private,那么删除这个变量会导致继承类程序重写。所以要声明为private条款23 使用非成员函数替换成员函数
如果一个方法只是调用了其他几个成员函数,没有必要将其设置为成员函数,把他放在外面,然后用相同的命名空间包裹就可以了条款24 如果成员函数的参数需要支持类型转换,则将其转为非成员函数
这是因为成员函数在某些情况下可能无法发挥作用。比如operator *只能支持该类型作为第一个参数。如果内置类型作为第一个参数的时候就会失效。条款25 swap函数与异常
swap是个有用的函数。为了实现高效率的swap,你需要设计一个swap成员函数来与另外一个对象进行交换。然后再命名空间设计一个非成员函数雨来调用上面的swap函数。最后特化std::swap来让编译器选择你自己的swap
第五章 有关函数的实现
条款26 延迟定义出现的顺序
C++对于不同行的顺序不能随意更改其顺序,这意味着只有用到什么再去定义什么更能符合过程,如果在刚开始就将所有的定义,但是程序一开始就返回,这就会带来不必要的构造与析构过程。条款27 避免类型转换
四种c++类型转换的使用场景虽然可以使用,但是如果使用了都会带来更大的问题。旧式的类型转换就更不能用了。条款28 避免返回handles指向对象内部成分
尽量避免对象内部的数据的指针被返回到对象外部,这会带来很大的问题。vector []运算符就是这种情况。这种情况是特例条款29 异常安全
C++异常是最难以处理的一件事情了。但是还是要保证异常。条款30 了解inline
inline是让编译器尽量避免栈的展开,而不是一定。八二法则告诉我们,程序只会花时间在20%的代码上,不一定见了函数就要都用inline。条款31 减少依赖——定义与声明相分离
两种处理方式——实施类与接口类。实施类就是使用另一个类来代理实现该类的功能。接口类就是使用面向对象的方法来将该类设计为接口。
第六章 面向对象设计
条款32 public继承意味着is-a关系
这意味着所有基类能够办到的事情派生类也能办到。但是派生类能够办到的基类不一定能办到条款33 继承时会发生名称遮掩
如果在派生类中声明了父类函数的另一个重载版本,会将父类的原始版本也一并覆盖,使得无法正确的链接到父类函数。可以使用using来表示使用父类的函数空间。条款34 区分接口继承和实现继承
纯虚函数是只继承接口,虚函数继承接口和默认实现,非虚函数是继承接口和强制实现条款35 不是只有虚函数一种实现
可以使用其他设计模式来代替虚函数的实现,例如仿函数条款36 不要重新定义非虚函数
省的到时候你都不知道具体是哪个被调用了。没错说的就是析构函数。条款37 不要重新定义缺省参数
这是因为缺省参数是静态确定的而不是动态确定的。你定义的那个不一定有用条款38 区分复合与继承
public继承是is-a关系。复合是has-a关系。例如set的实现,如果继承list就会有一些问题了。set应该复合list。条款39 private继承意味着根据其实现
private的使用频率比复合使用的频率要更低。有两种情况需要这样实现,第一种情况是派生类需要访问基类的protected成员。第二种情况是需要重新定义virtual函数(这种情况难道不应该设计一种中间类吗)。条款40 小心的使用多重继承
多重继承使用的很少。虚继承内最好不要包含任何成员。因为虚继承的成员初始化是在派生类内完成的。
第七章 泛型编程
条款41 了解隐式接口与编译器多态
就是静态多态。条款42 typename的双重含义
typename除了会在模板的template一行中使用,还会模板的处理中出现。当我们使用成员变量或者是成员类型时,编译器不知道用的是哪一个。默认使用的成员变量。加上typename来提醒编译器用的是成员类型条款43 继承一个模板类,对模板类内的符号要显示声明
这是因为模板类可能特化,如果特化,则可能有的符号不存在。所以需要显示的指示模板类内的符号,例如使用this指针或者是作用域条款44 template导致代码膨胀
template参数在传入一个非类型参数的时候,会生成多份代码。这些代码有一些方式可以避免重复生成,但是速度不如原来的快。条款45 运用成员函数模板接受所有兼容类型
类可以是模板的,成员函数也可以是模板的。条款46 需要类型转换时请为模板定义非成员函数
不仅要定义成非成员函数,还要定义成为friend函数。条款47 使用traits
traits是使用了模板编程与特化的性质实现的一个triats类,通过triats类可以获得想要的泛化类内的数据类型。条款48 template元编程
元编程指的是在编译期间就知道结果的编程方法。比如在编译期间处理输入。类似于C++的hello world的程序就是阶乘。
第八章 new 与 delete
条款49
了解new-handler的行为
就是不断尝试分配内存。我很好奇如果new-handler一直分配失败会不会出现卡死的现象。条款50
了解自定义new和delete的场合
貌似现在的new和delete性能都很高了。不用替换条款51
自定义new和delete要保持兼容性条款52
placement new 和placement delete
placement delete会在placement new出现错误的时候自动运行
第九章 现在的c++11
条款53
不要忽视warring条款54
熟悉tr1的标准程序库条款55
熟悉boost