Effective C++ 学习笔记1 定制new和delete

本文围绕C++的operator new和operator delete展开。介绍了它们分别用于分配单一对象和数组内存,以及new-handler函数的作用和设计要点。还提及了no throw new的局限性,阐述了自定义new和delete的理由,同时说明了operator new和delete使用中的一些注意事项,如内存分配异常处理等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. operator new 和 operator delete 只适合用来分配单一对象;
    Arrays 所用的内存由operator new[] 分配出来,并由operator delete[] 归还。
  2. 当operator new抛出异常以反映一个未获满足的内存需求之前,它会先调用一个客户指定的错误处理函数,new-handler.
  3. 客户可以通过调用set_new_handler来指定客户定制的new-handler函数
  4. 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”。
  5. 当operator new无法满足内存申请时,它会不断调用new-handler函数,知道找到足够内存,所以设计一个良好的new-handler函数必须做以下事情:
    (1)让更多的内存可以被使用
    (2)安装另一个new-handler
    (3)卸除new-handler
    (4)抛出bad_alloc
    (5)不返回,通常调用abort或exit
  6. 实现让每个类都有自己专属的new_handler,可以使用模板类来完成(怪异的循环模板模式 CRTP), 具体详见Effective C++ 条款49。
  7. 旧的编译器当无法分配足够内存时返回null,新一代的operator new则应该抛出bad_alloc异常,但很多的C++程序是在编译器开始支持新修规范前写出来的,C++标准委员会不想抛弃“侦测null”的族群,于是提供另一形式的operator new, no throw, 譬如:
    Widget pw1 = new (std::nothrow) Widget*
    尽管如此,它也只能保证,在分配内存时候不会抛出异常,但它无法避免构造函数中的异常。Nothrow new是一个颇为局限的工具,因为它只适用于内存分配,后继的构造函数调用还是可能抛出异常。
  8. 有许多理由需要写个自定义的new和delete:
    (1)为了检测运行错误, 例如在分配内存块的之前和之后添加一个signature来检测是否出现运行错误;
    (2)为了强化效能,编译器自带的new和delete功能强大,但是它是中庸的,不对特定的任何人有最佳表现,所以重写new和delete是获得重大效能提升的办法之一;
    (3)为了收集使用的统计数据;
    (4)增加分配和归还的速度;
    (5)为了降低缺省内存管理器带来的空间额外开销;
    (6)为了弥补缺省分配器中的非最佳齐位;
    (7)为了将相关对象成簇集中(placement版本);
    (8)为了获得非传统行为;
  9. operator new应该内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存需求,就应该调用new-handler;我们可以通过set_new_handler(0) 来找到目前的new-handler函数,然后再通过set_new_handler(new-handler)对其进行还原;
  10. operator new 如果申请内存size == 0, 将它视为1byte申请;
  11. 退出operator new无限循环的唯一方法:内存被成功分配或是new-handling函数做了:有更多的内存可用;安装另一个可用的new-handler;卸除new-handler;抛出bad_alloc异常;承认失败直接return;
  12. 当operator new成员函数被derived classes继承,可能会造成base class分配的长度不是实际需要分配的长度,解决方法是通过new的size参数与sizeof(base class)做对比,如果不相等,那么使用系统运行时的operator new函数来做真正的分配,注意这里已经将size==0的情况包含在内。
  13. operator delete应该在收到null指针时不做任何事,if (rawMemory == 0) return;
  14. 如果即将被删除的对象派生自某个base class而后者欠缺virtual析构函数,那么C++传给operator delete的size_t数值可能不正确,这是让base class拥有virtual析构函数的一个够好的理由。处理方法同12,如果要析构的size和sizeof(base class)不同,则使用系统运行时的operator delete。
  15. 如果一个带额外参数的operator new(placement new)没有“带相同额外参数”的对应版本operator delete(placement delete),那么当new的内存分配动作需要取消并恢复旧观时就没有任何的operator delete被调用。当然如果new的过程中没有发生异常,则调用delete一定是调用系统而不是placement delete, 换句话说,placement delete只有在内存分配失败时起作用。
  16. 当你声明了placement new和placement delete, 请确定不要无意识地遮掩了它们的正常版本。凡是想以自定形式扩充标准形式的客户,可利用继承机制及using声明式(让标准的new和delete不会被掩盖)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值