8 定制new和delete
~~~~~~~~~~~~~~~~~~
8.1 了解new-handler的行为
==========================
1. 当opeartor new无法满足某一内存分配需求时,它会抛出异常.在这之前,它会先调用一个客户指定的错误处理函数,所谓的new-handler
2. 用户必须通过调用set_new_handler来设置new-handler函数,set_new_handler的参数是指向new-handler函数的指针
3. new-handler函数应该没有参数,也不返回任何东西(void)
4. 当operator new无法满足内存申请时,它会 *不断* 调用new-handler函数,直到找到足够内存!
5. 一个设计良好的new-handler函数必须做以下事情中的一个或几个
* 让更多内存可被使用
一个做法是,程序一开始执行就分配一大块内存,然后当new-handler第一次调用,将它们释放给程序使用
* 安装另一个new-handler
(否则会不断调用这个new-handler,进入死循环)
* 卸除new-handler
也就是将null指针传给set_new_handler,这样operator new会在内存分配不成功时抛出异常
* 抛出bad_alloc
* 退出程序
通常调用abor或exit
6. 使用new (std::nothrow),如果分配内存失败,不会抛异常,而是返回NULL值,nothrow定义于<new>
8.2 写new和delete时需固守常规
==============================
1. operator new应该内含一个无穷循环,并在其中尝试分配内存,如果无法满足内存需求,就调用new-handler.
它也应该有能力处理0bytes申请.
由于类中的operator new成员函数会被子类继承,因此class专属版本则还需要处理"比正确大小更大的错误申请"
- //non-member operator new伪代码
- void* operator new(std::size_t size)throw(std::bad_alloc)
- {
- using namespace std;
- if(size == 0){
- size = 1; //处理0-bye申请,将它视为1-bye申请,因为C++不允许大小为0的对象
- }
- while(true){
- 尝试分配size bytes;
- if(分配成功){return 指向内存的指针;}
- //分配失败,找出目前的new-hander函数并调用
- new_handler globalHandler = set_new_handler(NULL);
- set_new_handler(globalHandler);
- if(globalHandler){
- (*globalHandler)();
- }else{
- throw std::bad_alloc();
- }
- }
- }
2. operator new[]唯一需要做的一件事就是分配一块未加工内存.
3. operator delete应该在收到null指针时,不做任何事.class专属版本则还应该处理"比正确大小更大的错误申请"
8.3 写了placement new也要写placement delete
============================================
1. 如果operator new接受的参数除了一定会有的那个size_t之外,还有其他参数,这便是个所谓的placement new.
2. 相应的placement delete指"参数个数和类型都与operator new相同的"operator delete
3. 运行期,若replacement new抛出异常,则系统会去找与placement new相对应的placement delete版本,若找不到则什么也不做.
但是placement delete只有在"伴随placement new调用而触发的构造函数"出现异常时才会被编译器自动调用.对一个指针显式调用delete不会导致调用placement delete.
4. 缺省情况下,C++在global作用域提供三种形式的operatornew
- * void* operator new(std::size_t)throw(std::bad_alloc); //normal new
- * void* operator new(std::size_t,void*) throw(); //placement new
- * void* operator new(std::size_t,const std::nothrow_t&)throw()//nothrow new
5. 当声明了专有类的new和delete之后,请注意,它会遮掩std的标准new和delete.