《Effective C++》:条款50:了解new和delete的合理替换时机

有人会想要替换掉编译器提供的operator new或operator delete,因为

写个定制的operator new和operator delete并不难。例如,写个global operator new,用于检测在分配区块的后面或前面写入数据。下面是个初步版本,有小错误,后面在完善。

signature=0xDEADBEEF;Byte;(std::size_t size) throw(std::bad_alloc){;size_t realSize=size+2*sizeof(int);//增加大小,塞入两个sinaturevoid* pMem=malloc(realSize);if(!pMem) throw bad_alloc();//将signarure写入内存最前后最后*(static_cast<int*>(pMem))=signarure;*(reinterpret_cast<int*>(static_cast<Byte*>(pMem)+realSize-sizeof(int)))=signature;return static_cast<Byte*>(pMem)+sizeof(int);}

暂且忽略之前所说的operator new内应该有个循环,反复调用new-handling。来说一下另外一个主题:对齐(alignment)。

许多计算机体系结构要求特定的类型必须放在特定的内存地址上。例如可能是指针的地址必须是4的倍数(four-byte aligned)或double的地址是8的倍数(eight-byte aligned)。没有这些约束可能会导致运行期硬件异常。有些体系结构要求没这么严格,没有字节对齐不会导运行效率低下。

C++要求所有operator new返回的指针都有适当的对齐(取决于数据类型)。malloc就是在这样的要求下工作。所以令operator new返回一个得自malloc的指针是安全的。但是上面实现中,我们偏移了一个int的大小,就不能保证其安全了。例如,如果返回double指针,就不是8字节对齐了。

像对齐这类技术细节,可以区分内存管理器的质量。写一个能够运行的内存管理器并不难,难的是让它总是能够高效优良的运作。一般来说,若非必要,,不要去写内存管理器。

很多时候也是非必要的。有些编译器已经在它们的内存管理函数中切换至调试状态(enable debugging)和志记状态(logging)。许多平台上有商业产品可以代替编译器自带的内存管理器,可以用它们来提高机能和改善效率。

另外一个选择是开源领域中的内存管理器。它们对许多平台都可以用。Boost程序库(条款 55)的Pool就是这样的一个分配器,它对常见的分配大量小内存很有帮助。一些小型开源内存分配器大多都不完整,缺少移植、线程安全、对齐等考虑。

本条款是在探讨何时需要在全局性的活class专属的基础上合理替换掉缺省的new和delete,前面说到了3点。这里继续。

总结

有许多理由需要写个自定的new和delete,包括改善效能、对heap运用错误进行调试、收集heap使用信息。

我无所事事的度过了今天,是昨天死去的人们所期望的明天。

《Effective C++》:条款50:了解new和delete的合理替换时机

相关文章:

你感兴趣的文章:

标签云: