EffectiveC++读书笔记——item50(什么时候替换new和delete)
- 创业
- 2025-09-03 06:39:02

在 C++ 中,有时候需要替换编译器提供的 operator new 和 operator delete 版本。下面详细介绍替换的原因、可能遇到的问题以及合适的替换时机,并给出相应的代码示例。
1. 替换 new 和 delete 的主要原因 监测使用错误:通过记录已分配地址和在分配块前后设置标志字节,可以检测内存泄漏、多次删除和数据上溢 / 下溢等错误。提升性能:编译器提供的默认版本是为多种用途设计的,采用中间路线策略。如果对程序的动态内存应用模式有充分理解,自定义版本可能运行更快且需要更少的内存。收集使用方法的统计数据:自定义版本可以方便地收集被分配区块大小、生存期、分配和释放顺序等信息。 2. 自定义 operator new 示例及问题以下是一个简单的自定义 operator new 示例,用于检测数据上溢和下溢:
#include <iostream> #include <new> static const int signature = 0xDEADBEEF; typedef unsigned char Byte; // 此代码存在缺陷 void* operator new(std::size_t size) throw(std::bad_alloc) { using namespace std; size_t realSize = size + 2 * sizeof(int); // 增加请求大小以容纳标志字节 void *pMem = std::malloc(realSize); // 调用 malloc 获取内存 if (!pMem) throw std::bad_alloc(); // 在内存的开头和结尾写入标志字节 *(static_cast<int*>(pMem)) = signature; *(reinterpret_cast<int*>(static_cast<Byte*>(pMem) + realSize - sizeof(int))) = signature; // 返回指向第一个标志字节之后的内存指针 return static_cast<Byte*>(pMem) + sizeof(int); }该代码存在一些问题,例如没有遵循 operator new 的 C++ 惯例(如未包含调用 new-handling function 的循环),更微妙的问题是可能存在排列对齐问题。
3. 排列对齐问题很多计算机架构要求特定类型的数据放置在具有特定性质的地址中,不遵守约束可能导致运行时硬件异常或性能下降。C++ 要求 operator new 返回适合任何数据类型排列的指针,上述代码返回的指针偏移了一个 int 大小,可能导致对齐不恰当。
4. 替换 new 和 delete 的合适时机 监测使用错误:记录已分配地址和检查标志字节,检测内存泄漏、多次删除和数据上溢 / 下溢等错误。收集使用统计数据:收集被分配区块大小、生存期、分配和释放顺序等信息。提升分配和回收速度:通用目的的分配器通常比自定义版本慢,特别是针对特定类型对象专门设计的自定义版本。单线程程序可以通过编写非线程安全分配器获得速度提升,但需确定这些函数是真正的瓶颈。 // 简单的单线程固定大小分配器示例 #include <vector> template <typename T> class FixedSizeAllocator { private: std::vector<T*> freeList; public: void* allocate() { if (freeList.empty()) { return ::operator new(sizeof(T)); } void* p = freeList.back(); freeList.pop_back(); return p; } void deallocate(void* p) { freeList.push_back(static_cast<T*>(p)); } }; 减少缺省内存管理的空间成本:通用目的的内存管理器通常比自定义版本使用更多的内存,针对小对象调谐的分配器可以消除这种成本。调整缺省分配器不适当的排列对齐:某些编译器提供的 operator new 可能不能保证特定类型(如 double)的动态分配按照要求的字节对齐,替换为保证对齐的版本可以提升性能。聚集相关的对象:使用 new 和 delete 的定位版本(placement versions),为特定数据结构创建独立的堆,降低页错误频率。获得不同寻常的行为:例如在共享内存中分配和回收区块,或用零覆盖被回收的内存以提高数据安全性。 总结要点 替换原因多样:有很多正当理由编写 new 和 delete 的自定义版本,包括改进性能、调试堆用法错误以及收集堆用法信息。注意排列对齐:自定义 operator new 时要注意排列对齐问题,确保返回的指针适合任何数据类型的排列。考虑多种因素:在决定替换 new 和 delete 时,要综合考虑性能、内存使用、错误检测等多种因素,并进行实际测试以确定是否真的有必要替换。EffectiveC++读书笔记——item50(什么时候替换new和delete)由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“EffectiveC++读书笔记——item50(什么时候替换new和delete)”