七、模板与泛型编程
41.了解隐式接口和编译器多态
1.类和模板都支持接口和多态。
2.类的接口是显式定义的——函数签名。多态是通过虚函数在运行期体现的。
3.模板的接口是隐式的(由模板函数的实现代码所决定其模板对象需要支持哪些接口),多态通过模板具现化和函数重载解析在编译期体现,也就是编译期就可以赋予不同的对象于模板函数。
42.了解typename的双重意义
1.声明模板参数时,前缀关键字class和typename可以互换。
2.请使用关键字typename标识嵌套从属类型名称;1(表明后面的那个东西是一个类型名称)但不得在base class lists(基类列)或成员初值列内以它作为base class修饰符。
43.学习处理模块化基类的名称
1.编译器往往会拒绝在模板化基类中寻找继承而来的名称,因为基类的模板化可能被特化而那个特化版本也许并不会提供某一接口。所以我们可以使用 “this->” 指定,或使用 “using” 告诉编译器假设它存在
44.将与参数无关的代码抽离 templates
templates 会生成多个 classes 和函数,所以任何 template 代码都不该与某个造成膨胀的 template 参数产生相依关系。
45.运用成员函数模板接受所有兼容类型
1.请使用成员函数模板生成 “可接受所有兼容类型” 的函数。即完成一些类型的指针向上转型(例如 Derive* -> Base*)。
2.如果声明的成员模板是用于 “泛化 copy 构造” 或 “泛化 assignment 操作” ,你还需要声明正常的 copy 构造和 assignment 操作符。
46.需要类型转换时请为模板定义非成员函数
1.为了让类型转换可能发生于所有实参上,我们需要一个非成员函数(条款 24)。在模板中,为了令这个函数被自动具现化,我们需要将它声明在类内部。为了在类内部声明非成员函数,唯一的办法是令它成为一个 friend。
47.请使用 traits classes(特性类)表现类型信息
Traits 不是 C++ 关键字或一个预先定义好的构件,而是一种技术,也是 C++ 程序员共同遵守的协议。它要求对于内置类型和用户自定义类型的表现必须一样好。Traits classes 使得 “类型相关信息” 在编译期可用,它们以 templates 和 “templates 特化” 完成实现。
使用重载函数的形式,可以使 Traits classes 在编译期完成对类型的检测。
具体可看STL中关于traits的用法。
48 . 认识 template 元编程
1.模板元编程(template metaprogramming TMP)可将工作由运行期移往编译期(编译器时间变长了,可执行文件变小了),因而得以实现早期错误侦测和更高的执行效率。上述 traits 就是 TMP 的应用。
2.TMP 可被用来生成 “基于政策选择组合” 的客户定制代码,而可用来避免生成对某些特殊类型不适合的代码。
八、定制new和delete
49.了解new-handler的行为
当operator new抛出异常以反映一个未获得满足的内存需求之前,它会先调用一个客户指定的错误处理函数,一个所谓的new-handler。,为了指定这个 处理内存不足的函数,客户必须调用sett_new_handler,这是声明与<new>的一个标准库函数
Set_new_handler的参数指向operatornew无法分配足够内存时该被调用的函数。,返回值指向被调用前正在执行(但马上就要被替换掉的)那个new-handler函数。
设计一个良好的new-handler必须:
- 让更多内存可被使用:程序一开始就分配一大块内存,然后当new-handler第一次被调用时,将他们还给程序使用。
- 安装另一个new-handler。
- 卸除new-handler。
- 抛出bad_alloc。
- 不返回,通常调用abort或exit。
如果需要让不同的class调用各自的专属new-handler,只需令每一个class提供自己的set_new_handler和operator new即可。
50.了解new和delete的合理替换时机
为什么要替换编译器提供的operator new和delete:
- 用来检测运用上的错误。编程错误可能导致数据over/under runs(写入点在分配区块尾端之后或之前)。如果我们自定义operator new可以额外空间放置特定byte patterns(签名),delete时检查签名是否原封不动,就可以志记错误。
- 为了强化效能
- 收集使用上的统计数据
- 增加分配和归还速度
- 降低缺省内存管理器带来的空间额外开销
- 弥补缺省分配器的非最佳齐位(内存对齐)
- 将对象成簇集中
- 获得非传统的行为
51.编写new和delete需固守常规
1.Opeartor new应该有一个无穷循环,并在其中尝试分配内存,如果无法满足内存需求就该调用new-handler
2.Operator delete应该在收到null指针时不做任何事。
52.写了placement new也要写placement delete
如果operatornew接受的参数除了一定会有的size_t之外还有其他,这便是所谓的placement new.
- 如果一个带额外参数的operator new没有带相同额外参数的对应版operator delete,当new的内存分配动作需要取消并恢复旧观时就没有任何operator delete被调用,所以需要有对应的placement operator delete
- 当你声明placement new 和placement delete时请不要无意识的遮掩了他们正常版本。