章节 | 标号 | 条款 | 细节 |
让自己习惯C++ | Item-1 | 视C++为一个语言联邦 | |
Item-2 | 尽量以const、enum、inline替换#define | ||
Item-3 | 尽可能使用const | ||
Item-4 | 确定对象被使用前已先被初始化 | ||
构造/析构/赋值 | Item-5 | 了解C++默默编写并调用那些函数 | |
Item-6 | 若不想使用编译器自动生成的函数,则明确拒绝 | ||
Item-7 | 为多态基类声明virtual析构函数 | ||
Item-8 | 别让异常逃离析构函数 | ||
Item-9 | 绝不在构造和析构过程中调用virtual函数 | ||
Item-10 | 令operator=返回一个reference to *this | ||
Item-11 | 在operator=中处理“自我赋值” | ||
Item-12 | 复制对象时务忘其中每一个成分 | ||
资源管理 | Item-13 | 以对象管理资源 | |
Item-14 | 在资源管理类中小心copying行为 | ||
Item-15 | 在资源管理类中提供对原始资源的访问 | ||
Item-16 | 成对使用new和delete时要采取相同形式 | ||
Item-17 | 以独立语句将newed对象置入智能指针 | ||
设计与声明 | Item-18 | 让接口容易被正确使用,不易被误用 | |
Item-19 | 设计class犹如设计type | ||
Item-20 | 宁以pass-by-reference-to-const替换pass-by-value | ||
Item-21 | 必须返回对象时,别妄想返回其reference | ||
Item-22 | 将成员变量声明为private | ||
Item-23 | 宁以non-member、non-friend替换member函数 | ||
Item-24 | 若所有参数皆需要类型转换,请为此采用non-member函数 | 唯有非成员函数才有能力“在所有实参身上实施隐式类型转换” | |
Item-25 | 考虑写出一个不抛出异常的swap函数 | ||
实现 | Item-26 | 尽可能延后变量定义式的出现时间 | |
Item-27 | 尽量少做转型动作 | ||
Item-28 | 避免返回handles指向对象内部成分 | ||
Item-29 | 为“异常安全”而努力是值得的 | ||
Item-30 | 透彻了解inlining的里里外外 | ||
Item-31 | 将文件间的编译依存关系降至最低 | ||
继续与面向对象设计 | Item-32 | 确定你的public继承塑模出is-a关系 | |
Item-33 | 避免掩饰继承而来的名称 | ||
Item-34 | 区分接口继承和实现继承 | ||
Item-35 | 考虑virtual函数以外的其他选择 | ||
Item-36 | 绝不重新定义继承而来的non-virtual函数 | ||
Item-37 | 绝不重新定义继承而来的(virtual)缺省参数值 | 绝不重新定义继承而来的non-virtual函数; virtual函数是动态绑定,缺省参数值是静态绑定 |
|
Item-38 | 通过复合塑模出has-a或“根据某物实现出” | ||
Item-39 | 明智而审慎的使用private继承 | private继承意味implemented-in-terms-of(根据某物实现出)。如果你让Class D以Private形式继承Class B,用意是为了采用class B内已经备妥的某些特性,而不是因为B对象和D对象存在任何观念上的关系。private继承意味只有实现部分被继承,接口部分应略去。 尽可能使用复合,必要时才使用private继承(protected成员或virtual函数牵扯进来时)。 private继承主要用于“当一个意欲成为derived class者想访问一个意欲成为base class者的protected成分,或为了重新定义一个或多个virtual函数”。 C++裁定凡是独立(非附属)对象都必须有非零大小。【EBO:empty base optimization】 |
|
Item-40 | 明智而审慎的使用多重继承 | MI:可能导致歧义、对virtual继续的需要 C++解析(resolving)重载函数调用的规则:在看到是否有个函数可取用之前,首先确认这个函数对此调用是最佳匹配,找出最佳匹配函数后才检验其可取用性。 virtual继承:使用virtual继承的那些classes所产生的对象往往比使用non-virtual继承的兄弟们体积大;访问virtual base classes 的成员变量时也比访问non-virtual base classes 的成员变量速度慢。 virtual base classes初始化的规则更复杂(virtual base的初始化责任是由继承体系中的最低层 class负责) |
|
模板与泛型编程 | Item-41 | 了解隐式接口和编译期多态 | 面向对象编程:总是以显示接口和运行期多态解决问题 Templates及泛型编程:隐式接口和编译期多态 重要性更高 编译期多态:以不同的template参数具现化function templates,会导致调用不同的函数,这就是所谓的编译期多态。 |
Item-42 | 了解typename的双重意义 | C++解析规则:如果解析器在template中遭遇一个嵌套从属名称,它便假设这个名称不是个类型,除非明确告诉它是(关键字typename)。 typename只被用来验明嵌套从属名称;其他名称不应该有它存在。 例外:typename不可以出现在base classes list内的嵌套从属类型名称之前,也不可在member initialization(成员初值列)中作为base class 修饰符。 |
|
Item-43 | 学习处理模板化基类内的名称 | C++拒绝在templatized base classes(模板化基类)内寻找继承而来的名称,除非:
|
|
Item-44 | 将与参数无关的代码抽离templates | 因非类型模板参数 (non-type template parameters) 而造成的代码膨胀,往往可 消除,做法是以函数参数或 class 成员变最替换 template 参数。 因类型参数 (type parameters) 而造成的代码膨胀,往往可降低,做法是让带有 完全相同二进制表述 (binary representations) 的具现类型 (instantiation types) 共享实现码。 working set:所谓 working set 是指对一个在“虚内存环境”下执行的进程 (process) 而言, 其所使用的那一组内存页 (pages)。 |
|
Item-45 | 运用成员函数模板接受所有兼容类型 | 必须同时声明泛化copy构造函数和正常的copy构造函数。(同样适用与assignment) 请使用成员函数模板(member function templates)生成“可接受所有兼容类型”的函数。 |
|
Item-46 | 需要类型转换时请为模板定义非成员函数 | function template实参推导过程中并不考虑采纳“通过构造函数而发生的隐式类型转换”。 在一个class template内,template名称可以被用来作为“template和其参数”的简略表达式。 当我们编写一个class template,而它所提供之“与此template相关的”函数支持“所有参数之隐式类型转换”时,请将那些函数定义为“Class template内部的friend函数”。
|
|
Item-47 | 请使用traits classes表现类型信息 | traits:允许在编译期间取得某些类型信息。他们以templates和“templates 特化”完成实现。 整合重载技术后(overloading)后,traits classes有可能在编译期间对类型执行if...else测试:
|
|
Item-48 | 认识template元编程 | 模板元(TMP,Template metaprogramming)程序:是以C++写成,执行与C++编译器内的程序。 由于TMP执行于C++编译期间,因此可将工作从运行期转移到编译期。这导致的结果:某些错误原本通常在运行期才能侦测到,现在可在编译期发现。 较小的可执行文件、较短的运行期、较少的内存需求。编译时间变长。 编译器必须确保所有源码都有效,纵使是不会被执行的代码。 |
|
定制new和delete | Item-49 | 了解new-handler的行为 | 当operator new抛出异常以反映一个未满足的内存需求之前,它会先调用一个客户指定的错误处理函数(new-handler)。为了指定这个用以“处理内存不足”的函数,客户必须调用set new_handler。 new-handler,是当operator new无法满足客户的内存需求时所调用的函数。 一个设计良好的new-handler必须做以下事情:
Nothrow new是一个颇为局限的工具,因为它只适用于内存分配(operator new),后续的构造函数调用还是可能抛出异常。 注意:STL容器所使用的heap内存是由容器所拥有的分配器对象(allocator objects)管理,不是被new和delete直接管理。 |
Item-50 | 了解new和delete的合理替换时机 | ||
Item-51 | 编写new和delete时需固守常规 | ||
Item-52 | placement new和placement delete要成对使用 | 如果operator new接受的参数除了一定会有的那个size_t之外还有其他,这便是个所谓的placement new。 伴随placement new调用而触发的构造函数“出现异常时:运行期系统寻找“参数个数和类型都与operator new相同”的某个operator delete,如果找到则调用,否则什么都不做。placement delete只有在“伴随placement new调用而触发的构造函数“出现异常时才会被调用。对一个指针施行delete绝不会导致调用placement delete。
|
|
杂项 | Item-53 | 不要轻易忽略编译器的警告 | |
Item-54 | 让自己熟悉包括RT1在内的标准程序库 | Technical Report 1:
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个由shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr,不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象也还是会被释放。它是一种弱引用。 weak_ptr常用函数 weak_ptr weak_ptr w = p ,p可以是一个shared_ptr或者weak_ptr,赋值后w与p共享对象 w.reset() 将w置为空 w.use_count() 与w共享对象的的shared_ptr的数量 w.expired() 若w.use_count()为0,返回true,否则返回false w.lock() 如果expired为true,返回一个空shared_ptr;否则返回一个指向w的对象的shared_ptr
TR1自身只是一份规范。为了获得TR1提供的好处,你需要一份实物。一个好的实物来源是Boost。 所有Boost组件都位于命名空间boost内,但TR1组件都置于std::tr1内,你可以这样告诉编译器,令它对待references to std::tr1就像对待references to boost一样。 namespace std { namespace tr1=::boost; //定义别名 } |
|
Item-55 | 让自己熟悉Boost | ||
参考博客: