在C++中,分配和歸還內(nèi)存時需要保持數(shù)組和非數(shù)組形式的操作符的匹配:
T *aT = new T; // 非數(shù)組
T *arrT = new T[16]; // 數(shù)組
delete aT; // 非數(shù)組
delete [] arrT; // 數(shù)組
aT = new T[1]; // 數(shù)組
delete aT; // 錯誤!應該采用數(shù)組形式的操作符
保持這些函數(shù)正確地成對使用很重要,因為數(shù)組的分配和歸還所使用的函數(shù)不同于非數(shù)組形式。對于數(shù)組而言,new表達式不是使用operator new為數(shù)組分配存儲區(qū),而是使用array new。類似地,delete表達式也不是調(diào)用operator delete來釋放數(shù)組的存儲區(qū),而是調(diào)用array delete。更確切的說,當分配一個數(shù)組時應該使用一個不同的操作符,即new[],而不是像分配一個非數(shù)組的對象那樣使用new操作符。規(guī)劃內(nèi)存的情形類似。
array new和array delete分別是operator new和operator delete數(shù)組版本的對應物,它們的聲明方式類似:
void* operator new(size_t) throw(bad_alloc); // operator new
void* operator new[](size_t) throw(bad_alloc); // array new
void operator delete(void*) throw(bad_alloc); // operator delete
void operator delete[](void*) throw(bad_alloc); // array delete
有關這些函數(shù)的數(shù)組形式最常出現(xiàn)的混亂情形,出現(xiàn)于一個特定的類或類層次結構使用成員operator new和operator delete定義了自己的內(nèi)存管理方式時:
class Handle
{
public:
// ...
void* operator new(size_t);
void operator delete(void*);
// ...
};
Handle類定義了非數(shù)組形式的內(nèi)存管理函數(shù),但它們并不被用于Handle數(shù)組的情形,對于數(shù)組的情形,調(diào)用的是全局array new和array delete:
Handle* arrHandle = new Handle[MAX]; // 調(diào)用::operator new[]
// ...
delete [] arrHandle; // 調(diào)用::operator delete[]
從邏輯上來說,只要聲明了非數(shù)組形式的函數(shù)(即operator new和operator delete),就應該為這些函數(shù)聲明數(shù)組的形式,在日常編程實踐中,這一點往往被忽視。如果目的是想調(diào)用全局的數(shù)組分配操作,那么,定義“僅僅轉(zhuǎn)發(fā)對全局形式的調(diào)用”的局部形式,可以讓事情變得更清晰:
class Handle
{
public:
// ...
void* operator new(size_t);
void operator delete(void*);
void* operator new[](size_t n)
{
return ::operator new(n);
}
void operator delete[](void* p)
{
::operator delete(p);
}
// ...
};
如果目的是禁止分配Handle數(shù)組,那么可以將數(shù)組形式的函數(shù)聲明為private并且不提供定義。
另外一個易產(chǎn)生混亂和錯誤的地方在于,傳遞給array new的那個表示大小的參數(shù)值,取決于函數(shù)是如何被調(diào)用的。當operator new在一個new表達式中被隱式地調(diào)用時,編譯器會決定需要多少內(nèi)存,并將該數(shù)量作為參數(shù)傳遞給operator new。這個數(shù)量就是正在分配的對象的大小:
aT = new T; // 調(diào)用operator new(sizeof(T());
也可以直接調(diào)用operator new,在這種情況下,必須明確指明希望分配的字節(jié)數(shù):
aT = static_cast<T*>(operator new(sizeof(T)));
也可以直接調(diào)用array new:
arrT = static_cast<T*>(operator new[](sizeof(T) * 16));
然而,當通過new表達式隱式地調(diào)用array new時,編譯器常常為略微增加一些內(nèi)存請求:
arrT = new T[16]; // 請求內(nèi)存為* sizeof(T) + delta字節(jié)
所請求的額外空間一般由運行期內(nèi)存管理器(runtime memory manager)來記錄關于數(shù)組的一些信息,這些信息(包括分配的元素個數(shù)、每個元素的大小等)對于以后回收內(nèi)存是必不可少的。不過,事情遠沒有這么簡單,編譯器未必為每一個數(shù)組分配都請求額外的內(nèi)存空間,并且對于不同的數(shù)組分配而言,額外請求的內(nèi)存空間大小也會發(fā)生變化。
請求內(nèi)存數(shù)量上的區(qū)別通常只有在編寫非常底層的代碼時才需要考慮,在這種情形下,數(shù)組的存儲區(qū)被直接處理。如果打算編寫底層代碼,通常最簡單的做法是避免直接調(diào)用array new以及編譯器所執(zhí)行的有關干預,取而代之的是,使用普通的operator new。
posted on 2011-06-29 08:47
水 閱讀(2878)
評論(0) 編輯 收藏 引用 所屬分類:
c/c++基礎知識