49. 了解new-handler的行为
49.1 set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用。
49.2 一个设计良好的new-handler函数必须:
a. 让更多内存可被使用(程序一开始分配一大块内存)。
b. 安装另一个new-handler。做法之一是令new-handler修改"会影响new-handler行为"的
static数据、namespace数据或global数据。
c. 卸除new-handler。将null指针传给set_new_handler,内存分配不成功时抛出异常。
d. 抛出bad_alloc(或派生自bad_alloc)的异常(不被operator new捕捉)。
e. 不返回。通常调用abort或exit。
49.3 Nothrow new是一个颇为局限的工具,因为它只适用于内存分配,后继的构造函数调用还
是可能抛出异常。
49.4 CRTP(curiously recurring template pattern)奇异递归模板模式
一个类X继承自一个模板化的基类A,而A 又以X作为类型参数。CRTP可以被用于实现编译
期多态(静态多态),其中基类A用来定义(暴露)接口,派生类X用来实现这些接口。
50. 了解new和delete的合理替换时机
为什么会需要替换编译器提供的operator new或operator delete?
a. 用来检测运用上的错误。数据"overruns"(写入点在分配区块尾端之后)或"underruns"(写入
点在分配区块起点之前)。自定义new可以超额分配内存,以额外的空间放置特定的byte
patterns(即签名signatures)。自定义delete则可以检查签名是否正确,若否则表示在分配
区的某个时间点发生了overrun或underrun,此时可以log事件。
b. 为了收集使用上的统计数据。
c. 为了增加分配和归还的速度(强化效能)。定制版的new和delete比缺省版本更快。
d. 为了降低缺省内存管理器带来的空间额外开销(强化效能)。定制版的new和delete比缺省版
本更省空间。
e. 为了弥补缺省分配器中的非最佳齐位。如new时保证8-byte齐位。
f. 为了将相关对象成簇集中。构建单独的heap,将数据集中在尽可能少的内存页。
g. 为了获得非传统的行为。如包装C API,delete时擦除内容等。
51. 编写new和delete时需固守常规
51.1 自定义operator new
a. 应该内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存需求,就应该调用
new-handler。
b. 应该有能力处理0 byte申请(视为1 byte申请)。
c. 类的专属版本应该能处理"与正确大小不一致的(错误)"申请(交给标准operator new)。
51.2 自定义operator delete
a. 应该在收到null指针时不做任何事。
b. 类的专属版本应该能处理"与正确大小不一致的(错误)"申请(交给标准operator delete)。
52. 写了placement new也要写placement delete
如果operator new接受的参数除了一定会有的size_t之外还有其它,这就是placement new。
52.1 当你写了一个placement new,确保也写了对应的placement delete。如果没有这样做,你的程序可能会发生隐藏的内存泄漏。
52.2 当你声明placement new和placement delete,请确保没有掩盖它们的正常版本(条款33)。
缺省情况下,global作用域的operator new:
a. void* operator new(std::size_t) throw(std::bad_alloc); //normal new
b. void* operator new(std::size_t,void*) throw(); //placement new
c. void* operator new(std::size_t,const std::nothrow_t&) throw();//placement new