10.如果寫了operator new,就要同時寫operator delete。
為什么要寫自己的operator new和delete,首先這不叫重載,這叫隱藏。 new只是用來申請空間,而構造函數是在申請的空間的基礎上繼續初始化。
為了效率。缺省的operator new 進行內存分配是并不僅僅分配一塊所需大小的內存,因為delete釋放內存時要知道指針所指向內容的大小,所以,new時會有一個塊來儲存內存塊的大小,而delete時,會根據這個大小來判斷刪除內存大小。所以當一個類本身很小的時候,這樣做,既浪費時間于內存大小的判斷,也浪費空間于內存大小的保存。對于某些類較小,且需要一定數量的這些小對象來儲存數據時,最好能寫一個operator new 來節約空間與時間。
而由于自己的Operator new申請的內存塊中沒有保存內存塊的大小,導致使用缺省的delete時,會導致不可預測的后果。所以若寫了operator new ,就必須同時寫operator delete。
一般解決方法是 申請一大塊內存,作為內存池,將其分為若干塊,每塊大小正好為儲存對象的大小。當前沒有被使用時。
嘗試將這種固定大小內存的分配器封裝起來。
~~~
//內存池的實現。
class Pool{
public:
Pool (size_t n,int size);
void* alloc(size_t n);//為一個對象分配足夠的內存
void free(void* p,size_t n);//將p指定的內存返回到內存池。
~Pool();//釋放內存池中的全部資源
private:
void* block;
const int BLOCK_SIZE;//池內存放塊的數量
void* list;
};
Pool::Pool(size_t n,int size):BLOCK_SIZE(size){
block = ::operator new(n*size);
int i;
for(i = 0;i<BLOCK_SIZE -1;i++){
*(unsigned int*)((unsigned int)block + n*i) =
(unsigned int)block + n*(1+i);
}
*(unsigned int*)((unsigned int)block + n*i) = 0;
list = block;
}
void* Pool::alloc(size_t n){
void* p = list;
if(p){//如果自由鏈表中還有元素,即還有空間
list = (void*)*(unsigned int *)list;
return p;
}else{
throw std::bad_alloc();
}
return p;
}
void Pool::free(void* p,size_t n){
if(0 == p)return;
*(unsigned int*)((unsigned int)p) = (unsigned int)list;
list = (void*)p;
}
Pool::~Pool(){
delete block;
}
class A{
public:
int a;
static void* operator new (size_t size);
static void operator delete (void* p,size_t size);
A(int x){a = x;}
private:
static Pool memPool;
};
Pool A::memPool(sizeof(A),10);
inline void* A::operator new(size_t size){
return memPool.alloc(size);
}
inline void A::operator delete(void* p,size_t size){
memPool.free(p,size);
}
int main(){
A* list[10];
for(int i = 0 ; i < 10;i++){
list[i] = new A(i);
}
int i = 0;
for(int i = 0 ; i < 10;i++){
delete list[i];
}
i = 1;
for(int i = 10 ; i < 20;i++){
list[i-10] = new A(i);
}
for(int i = 0 ; i < 10;i++){
delete list[i];
}
system("pause");
}
~~~
這是一個內存池的實現,結果感覺雖然實現了內存池的基本功能,但寫的不好看。。。譬如一些問題沒有解決,如果要求內存大于池的最大容量的處理,以及釋放池內元素時,如果重復釋放需要進行一些判斷此塊內存釋放已釋放。
忽略上面代碼,簡單分析一下內存池的基本功能:alloc 為對象申請空間的請求提供內存,而free釋放對象現在所在的內存。
這里說的寫了 operator new 就要寫對應的operator delete,因為你在自己寫的new中一定會定義一些其他的操作,使的數據的組織結構不是一個簡單的new就實現的,可能有多塊動態地址,或者可能像內存池中并沒有實際的去申請新的空間,所以一定要根據自己寫的new中的操作,設計對應的delete操作。