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