自己重写operator new时,很重要的一点是函数提供的行为要和系统缺省的operator new一致。实际做起来也就是:要有正确的返回值;可用内存不够时要调用出错处理函数;处理好0字节内存请求的情况。此外,还要避免不小心隐藏了标准形式的new。
非类成员形式的operator new的伪代码:
void * operator new(size_t size) // operator new还可能有其它参数
{
if (size == 0) // 处理0字节请求时,
{
size = 1; // 把它当作1个字节请求来处理
}
while (1)
{
分配size字节内存;
if (分配成功)
return (指向内存的指针);
// 分配不成功,找出当前出错处理函数
new_handler globalhandler = set_new_handler(0);
set_new_handler(globalhandler);
if (globalhandler) (*globalhandler)();
else throw std::bad_alloc();
}
}
为特定类写的new往往没有考虑该类被继承的情况,使用sizeof(父类)获得大小,但是如果发生子类调用父类的new时,往往
会出错,子类的size往往大于父类的size。最好父类的new应该这么写:
void * base::operator new(size_t size)
{
if (size != sizeof(base)) // 如果数量“错误”,让标准operator new,精华部分。
return ::operator new(size); // 去处理这个请求
//
... // 否则处理这个请求
}
对于operator delete(以及它的伙伴operator delete[]),情况更简单。所要记住的只是,c++保证删除空指针永远是安全的,所以你要充分地应用这一保证。
下面是非类成员形式的operator delete的伪代码:
void operator delete(void *rawmemory)
{
if (rawmemory == 0) return; //如果指针为空,返回
//
释放rawmemory指向的内存;
return;
}
这个函数的类成员版本也简单,只是还必须检查被删除的对象的大小。假设类的operator new将“错误”大小的分配请求转给::operator new,那么也必须将“错误”大小的删除请求转给::operator delete:
void base::operator delete(void *rawmemory, size_t size)
{
if (rawmemory == 0) return; // 检查空指针
if (size != sizeof(base)) // 如果size"错误",
{
::operator delete(rawmemory); // 让标准operator来处理请求
return;
}
释放指向rawmemory的内存;
return;
}
有关operator new和operator delete(以及他们的数组形式)的规定不是那么麻烦,重要的是必须遵守它。只要内存分配程序支持new-handler函数并正确地处理了零内存请求,就差不多了;如果内存释放程序又处理了空指针,那就没其他什么要做的了。至于在类成员版本的函数里增加继承支持,那将很快就可以完成。