1. 实现定制的operator new和operator delete需要满足一定的要求.
以operator new而言:实现一致性operator new必须返回正确的值;内存不足时必得调用new-handling函数;必须有对付零内存需求的准备;需避免不慎掩盖正常形式的new;如果有能力供应客户申请的内存,就返回一个指针指向该内存,反之就遵循条款49的规则并抛出bad_alloc异常;应该内含一个无限循环,知道成功分配内存或new-handling完成其功能......
以上的要求中"必须有对付零内存需求的准备"指的是即使客户要求0 bytes,operator也得返回一个合法指针.
2. 下面是一个non-member operator new伪码:
void* operator new(std::size_t size) throw(std::bad_alloc){ using namespace std; if(size==0) size=1; while(true){ 尝试分配size bytes; if(分配成功) return(一个指针,指向分配而来的内存); new_handler globalHandler=set_new_handler(0); set_new_handler(globalHandler); if(globalHandler) (*globalHandler)(); else throw std::bad_alloc(); } }
需要注意的是,operator new成员函数会被derived classes继承,这会导致某些有趣的复杂度.写出定制型内存管理器的一个常见理由是为针对某特定class的对象分配行为提供最优化,而不是为了该class的任何derived class,也就是说,这对某个类设计的operator,其行为可能很典型的只为大小刚好为该类型对象代销大小而设计.然而一旦被继承下去,有可能base class的operator new被调用用以分配derived class对象:
class Base{ public: static void* operator new(std::size_t size) throw(std::bad_alloc); ... }; class Derived:public Base{ ... }; Derived*p =new Derived; //这里调用的是Base::operaotr new!
Base class专属之operator new往往并不是被用来为Derived class对象分配内存,解决方法就是在"内存申请量错误"的调用行为改采标准的operator new:
void * Base::operator new(std::size_t size) throw(std::bad_alloc){ if(size!=sizeof(Base)) return ::operator new(size); ... }
如果要实现operator new[]的定制版,那么operator new[]唯一要做的就是分配一块内存,而无法对array内尚未存在的元素做任何事情,设置无法计算每个元素对象有多大,实际上,C++标准中operator new[]的缺省操作是经由operator new完成的(http://www.cplusplus.com/reference/new/operator%20new[]/?kw=operator%20new[]).
operator delete的情况比较简单,唯一需要注意的是C++保证"删除null指针永远安全",下面是non-member operator delete的伪码:
void operator delete(void* rawMemory) throw(){ if(rawMemory==0) return; 归还rawMemory所指内存; }
operator delete的member版本也比较简单,只需要多加一个动作检查删除数量.万一class专属的operator new将大小有误的分配行为转交::operator new执行,大小有误的删除行为也必须转交::operator delete执行:
class Base{ public: static void* operator new(std::size_t size) throw(std::bad_alloc); static void operator delete(void* rawMemory,str::size_t size) throw(); ... }; void Base::operator delete(void* rawMemory,std::size_t size) throw(){ if(rawMemory==0) return; if(size!=sizeof(Base)){ ::operator delete(rawMemory); return; } 现在,归还rawMemory所指内存; return; }
需要注意的是,如果即将被删除的对象派生自某个base class而后者欠缺virtual析构函数,那么C++传给operator delete的size_t数值可能不正确.也就是说,operator delete的正常运作依赖于析构函数的正常运作(如果有析构函数的话).