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中。