条款50:了解 new 和 delete 的合理替换时机(Understand when it makes sense to replace new and delete)

条款50:了解 new 和 delete 的合理替换时机

1.1 替换理由

需要替换operator new 或 operator delete的三大理由:

  1. 用来检测运用上的错误。
    如果令operator new持有一串动态分配所得地址,而operator delete将地址从中移除,就很容易检测内存泄露或重复delete的错误用法。此外,以额外空间放置特定的 “签名 ”,可以解决“overruns”(写入点在分配区块尾端之后) 和 “underruns”(写入点在分配区块起点之前)
static const int signature = 0xDEADBEEF;
typedef unsigned char Byte;
// 这段代码有一些缺陷,例如不能保证内存对齐
void* operator new(std::size_t size) {
    using namespace std;
    size_t realSize = size + 2 * sizeof(int); // 增加请求的大小,所以2个签名也将适合里面
    void* pMem = malloc(realSize); // 调用malloc来获取实际的内存
    if (!pMem) throw 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);    // 返回一个指向第一个签名后面的内存的指针
}
  1. 为了强化效能。
    默认的实现对多种情况都相当有效,但对任何情况都不是最佳效果。
  2. 为了收集使用上的统计数据。
    分配区块的大小分布;寿命分布;它们是倾向于按照FIFO、LIFO的顺序分配和释放,还是更接近随机的顺序?在执行的不同阶段是否有不同的分配/释放模式……

1.2 详细总结

  1. 提高分配和释放的速度。
    例如:编译器的内存管理器是线程安全的,如果你的程序是单线程的,替换为一个不是线程安全的分配器可能会提高速度。
  2. 把相关的物体聚集在一起。
    例如:如果你知道一些特定的数据结构通常一起使用,那么为这些数据结构创建一个单独的堆是有意义的。这样可以降低“内存页错误(page faults)”的频率。
  3. 降低缺省内存管理器带来的空间额外开销。
    例如:为小对象调优的分配器基本上可以消除额外的开销。
  4. 弥补缺省分配器中的非最佳齐位。
    例如:将默认new运算符替换为能够确保8字节对齐的版本,可以大幅提高程序性能(如果编译器本身不是这样做的话)。
  5. 获得非传统的行为。
    例如:你可以编写一个自定义delete运算符,用0重写已释放的内存,以提高应用程序数据的安全性。

1.3 总结

编写自定义版本的new和delete有很多合理的理由,包括改进性能、堆使用错误的调试和收集堆使用信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值