[笔记]《Effective C++》第八章Customizing new and delete
条款49:Understand the behavior of the new-handler.
- 当operator new无法满足某一内存分配需求时,它会抛出异常。当operator new抛出异常以反映一个未获满足的内存需求之前,它会先调用一个客户指定的错误处理函数,一个所谓的new-handler。
- 为了指定这个“用以处理内存不足”的函数,客户必须调用set_new_handler,那是声明于
的一个标准程序库函数:
namespace std{
typedef void(*new_handler)( );
new_handler set_new_handler(new_handler p) throw();
}
- new_handler是个typedef,定义出一个指针指向函数,该函数没有参数也不返回任何东西。set_new_handler则是“获得一个new_handler并返回一个new_handler”的函数。
- 一个设计良好的new-handler函数必须做以下事情:
- 让更多内存可被使用。
- 安装另一个new-handler。
- 卸除new-handler,也就是将null指针传给set_new_handler。
- 抛出bad_alloc (或派生自bad_alloc)的异常。
- 不返回,通常调用abort或exit。
条款50:Understand when it makes sense to replace new and delete.
替换编译器提供的operator new或operator delete的理由:
最常见的三个:
- 用来检测运用上的错误。各式各样的编程错误可能导致数据 "overruns"(写入点在分配区块尾端之后)或 "underruns"(写入点在分配区块起点之前)。如果我们自行定义一个 operator news,便可超额分配内存,以额外空间(位于客户所得区块之前或后)放置特定的byte patterns(即签名,signatures)。
- 为了强化效能。如果你对你的程序的动态内存运用型态有深刻的了解,通常可以发现,定制版之 operator new和operator delete性能胜过缺省版本。
- 为了收集使用上的统计数据。
其他理由:
- 为了增加分配和归还的速度。
- 为了降低缺省内存管理器带来的空间额外开销。
- 为了弥补缺省分配器中的非最佳齐位(suboptimal alignment)。
- 为了将相关对象成簇集中。
- 为了获得非传统的行为。
条款51:Adhere to convention when writing new and delete.
- 实现一致性operator new必得返回正确的值,内存不足时必得调用new-handling函数(见条款49),必须有对付零内存需求的准备,还需避免不慎掩盖正常形式的new。
- C++规定,即使客户要求0 bytes,operator new也得返回一个合法指针。
- operator new应该内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存需求,就该调用new-handler以做到:让更多内存可用、安装另一个new-handler、卸除new-handler、抛出bad_alloc异常(或其派生物),或是承认失败而直接return。
- 如果你决定写个operator new[],记住,唯一需要做的一件事就是分配一块未加工内存(raw memory)。
- C++保证“删除null指针永远安全”。operator delete应该在收到null指针时不做任何事。
条款52:Write placement delete if you write placement new.
- 当你写一个placement operator new,请确定也写出了对应的placementoperator delete。如果没有这样做,你的程序可能会发生隐微而时断时续的内存泄漏。
- 如果operator new接受的参数除了一定会有的那个size_t之外还有其他,这便是个所谓的placement new。下面的operator new就是个placement版本。
class Widget{ public: ... static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc); //非正常形式的new static void operator delete(void* pMemory std::size_t size) throw(); //正常的class专属delete ... };
- 如果一个带额外参数的operator new没有“带相同额外参数”的对应版operator delete,那么当new的内存分配动作需要取消并恢复旧观时就没有任何operator delete会被调用。
- placement delete只有在“伴随placement new调用而触发的构造函数”出现异常时才会被调用。对着一个指针施行delete绝不会导致调用placement delete。
- 如果operator new接受的参数除了一定会有的那个size_t之外还有其他,这便是个所谓的placement new。下面的operator new就是个placement版本。
- 由于成员函数的名称会掩盖其外围作用域中的相同名称,你必须小心避免让class专属的news掩盖客户期望的其他news(包括正常版本)。