第8章 定制new和delete
条款49:了解new-handler的行为
- 当operator new无法满足某一内存分配需求时,它就会抛出异常。它就会调用一个用户指定的错误处理函数new-handler(它其实是一个typedef),其实调用的是set_new_handler函数。
- set_new_handler:获得一个new_handler并返回一个new_handler 的函数。
- 当operator new无法满足内存申请时,它就会不断调用new-handler函数,直到找到足够内存。
- 一个设计良好的new-handler函数应该做以下事情:
(1) 让更多内存可以被使用:程序一开始的时候就分配一大块空间,当new-handler第一次被调用的时候,将它们释放给程序使用。
(2)安装另一个new-handler。目前的new-handler无法取到更多可用的内存,就找一个可以替换自己的new-handler,修改static数据、namespace数据和global数据。
(3)卸除new-handler,将null指针传给set_new_handler。一旦没有安装任何new-handler,operator new会在内存分配不成功时抛出异常。
(4)抛出bad_alloc的异常。这样的异常会传播到内存索引处。
(5)不返回,通常调用abort或者exit。
条款50:了解new和delete的合理替换时机
1.替换编译器提供的operator new或opertor delete的三个理由:
- 用来检测运用上的错误。
(1)如果new成功 ,delete失败会导致内存泄漏。
(2)如果在new所得内存上多次delete就会导致不确定行为。 - 为了强化效能。
(1)编译器所带的operator new和operator delete主要是满足大多数情况,对每个人都适度的好,但不对特定任何人有最佳表现。
(2)因为,我们要自己定制适合自己的operator new和operator delete,提升性能。 - 为了收集使用上的统计数据
(1)自定义的operator new 和operator delete 能使我们收集信息:比如你的软件如何使用其动态内存;分配区块内存的大小分部如何;寿命如何等。
2.齐位:
计算机体系结构要求特定的类型必须放在特定的内存地址上。C++要求所有operator news返回的指针都有适当的对齐。
3.什么时候可以在“全局性的”或者“class 专属的”基础上合理替换缺省的new和delete的意义? - 为了检测运行错误
- 为了收集动态分配内存之使用统计信息。
- 为了增加分配和归还的速度。(泛用型分配器往往比定制型分配器慢,特别是当定制型分配器专门针对特定类型之对象而设计时。
- 为了降低缺省内存管理器带来的空间额外开销。(泛用型分配器往往比定制型分配器使用更多的内存,常常在每一个分配区块身上招引某些额外开销)
- 为了弥补缺省分配器中的非最佳齐位。
- 为了将相关对象成簇集中。(前提:已经知道某个数据结构往往被一起使用。目的:处理数据时将“内存页错误”的频率降至最低。TODO:为此数据结构创建一个heap。它们被成簇集中在尽可能少的内存页中。
- 为了获取非传统的行为。想做编译器提供的operators new 和delete没做的事情,你就可以自定制一个。
条款51:编写new和delete时固守常规
- perator new的返回值:成功->返回一个指针指向那块内存;失败->调用new-handing函数->抛出一个bad_alloc异常。
- operator new应该内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存需求,就应该调用new-handler。它也应该有能力处理0bytes申请->1bytes
- operator delete应该在收到null指针时不做任何事情。
条款52:写了placement new 也要写placement delete
- 什么是placement new:placement new就是在用户指定的内存位置上构建新的对象,这个构建过程不需要额外分配内存,只需要调用对象的构造函数即可。
- 当时只使用正常形式的new和delete,运行期系统就可以找到new->delete。然而当你开始声明非正常形式的operator new,该调用那个delete就不知道了。