10、如果你写了一个operator new,请对应写一个operator delete
1、何时需要写一个operator new
缺省版的operator new和delete功能已经足够了,但不可避免的是他可能需要花费更多的内存,来提高效率。对于一些需要动态分配大量小额空间的程序而言,更需要提高效率。
class AirplaneRep {...};//表示一个Airplane对象
class Airplane {
public:
...
private:
AirplaneRep *rep;//指针,指向一个Airplane对象
};
如上,Airplane只内含一个指针,当调用operator new时获得的内存要比存储该指针的所需内存多,因为要让operator new与operator delete沟通。为了让operator delete知晓operator new分配了多少内存,通常要在他所传回的内存前加挂一些数据,来说明配置的区块大小。
对于小型对象如Airplane而言,这个额外的内存可能比真正需要的内存都多。若软件运行在内存十分宝贵的环境下,用缺省的operator new分配内存就比较奢侈了。此时,可以根据每个Airplane对象的大小相同,撰写一个operator new,而不需要加挂额外数据。
为此,撰写operator new,一种方法是:先用默认的operator new配置一大块内存,可容纳大量Airplane对象。而每一个Airplane对象需要的内存都从这块内存挖取。剩余尚未被利用的内存用链表来管理:利用union,当内存未被配置时,他是链表的next指针;当内存被配置为Airplane对象时,他是*rep。
class Airplane {
public:
static void * operator new (size_t size);
...
private:
union {
AirplaneRep *rep;
Airplane *next;
};
static const int BLOCK_SIZE;
static Airplane *headofFreeList;
};
这里,添加了operator new声明、union、常数(指定每个被配置区块的大小)、static指针(记录freelist的头部,整个类共享一个)。
void * Airplane::operator new (size_t size)
{
if(size != sizeof(Airplane))
return ::operator new(size);
Airplane *p = headofFreeList;
if(p)
headofFreeList = p->next;
else {
Airplane *newBlock = static_castz<Airplane *>(::operator new(BLOCK_SIZE * sizeof(Airplane)));
for(int i = 1; i < BLOCK_SIZE; ++i)
newBlock[i].next = &newBlock[i + 1];
newBlock[BLOCK_SIZE - 1].next = 0;
p = newBlock;
headofFreeList = &newBlock[1];
}
return p;
}
Airplane *Airplane::headofFreeList;
const int Airplane::BLOCK_SIZE = 512;
2、为啥要对应写一个operator delete
3、对应写一个operator delete
class Airplane {
public:
...
static void operator delete (void *deadObject, size_t size);
};
void Airplane::operator delete (void *deadObject, size_t size)
{
if(deadObject == 0) return;
if(size != sizeof(Airplane)) {
::operator delete(deadObject);
return;
}
Airplane *carcass = static_cast<Airplane *>(deadObject);
carcass->next = headofFreeList;
headofFreeList = carcass;
}
这里,使用delete并没有释放这些内存,而是把它放回内存池,即freelist内,这些内存仍在我们的掌控之内,故没有发生内存泄漏。同时,内存池的策略会使得即便频繁使用new、delete也不会那么慢。
class Pool {
public:
Pool (size_t n);
void * alloc (size_t n);
void free (void *p, size_t n);
~Pool ();
};
class Airplane {
public:
...
static void * operator new (size_t size);
static void operator delete (void *p, size_t size);
private:
AirplaneRep *rep;
static Pool memPool;
};
inline void * Airplane::operator new (size_t size)
{ return memPool.alloc(size); }
inline void Airplane::operator delete (void *p, size_t size)
{ memPool.free(p, size); }
Pool Airplane::memPool(sizeof(Airplane));
如此,Airplane与内存管理的细节没什么关系,都被隐藏在Pool中。