Item5:使用相同形式的new和delete
簡單的說,就是單個對象和數組要區分對待。C++使用[]區分這是單個對象還是數組,所以new中有[]的時候,請用delete[]。
Item6:記得在destructor中以delete對付pointer member
這條為了防止記憶體泄露,具體說來要做三件事情:
- 每個建構函式中將該指標初始化
- 每個賦值運算子中將原有記憶體刪除,重新設定一塊
- 每個解構函式中,delete這個指標
Item7:為記憶體不足的狀況預作準備
operator new申請記憶體得不到滿足時,在拋出std::bad_alloc之前會調用使用者佈建的handler,該調用找到足夠的記憶體才停止
typedef void(*new_handler)();
new_handler set_new_handler(new_handler p) throw(); |
因此,自己定義new handler需要遵循以下原則:
- 讓更多記憶體可用
- 自己處理不了的情況下,安裝一個不同的new handler
- 卸載這個new handler,拋出std::bad_alloc
- 直接調用abort或者exit
現在標準的operator new的行為時拋出一個std::bad_alloc的異常,其實,現在很少有情況會無法申請到記憶體,按照標準的做法即可。在拋出bad_alloc異常之後,做好log記錄和分析,一旦遇到這種情況,加記憶體就是了。
Item8:撰寫operator new和operator delete時應遵行的公約
自己寫operator new,要和預設的行為保持一致,詳細說來,new應該遵循的公約如下:
void * operator new(size_t size)
{
if(size==0){ //1.大小為0的new也可以成功
size=1;
}
while(true){ //2.不斷迴圈,嘗試申請記憶體
if(alloc success) return *pointer //3.成功返回指標
//4.不成功,處理錯誤
new_handler globalHandler = set_new_handler(0);
set_new_handler(globalHandler);
if(globalHandler) (*globalHandler)();
else throw std::bad_alloc(); //5.沒有處理函數,則拋異常
}
} |
delete應該遵循的則很簡單,即刪除一個null指標永遠是安全的
void operator delete(void * rawMemory)
{
if(rawMemory ==0 ) return;
否則再刪除記憶體
} |
Item9:避免遮掩了new的正規形式
C++中,內部scope中的聲明會遮掩外部的相同名稱,條款9說明了一個特殊情況,自己寫了一個定製的operator new,接收一個new_handler做額外的參數如下
void * operator new(size_t size, new_handler p) |
這個operator new會遮掩預設的operator new,使用者無法調用預設的new操作,針對這個情況,有兩種解決方案,一種是再聲明一個operator new(size_t size),另一種則是採用預設參數operator new(size_t size, new_handler p=0)
Item10:如果你寫了一個operator new,請對應寫一個operator delete
條款10其實說明使用operator new的原因:提高記憶體空間使用效率。
預設的operator new需要在返回指標的前方使用一點空間記錄該指標佔用的大小(該空間稱作cookie),用於delete的正常運行。自己重載operator new,則可以自己進行管理這個區塊,減少記憶體使用量
實現記憶體池,每次從記憶體池中申請,若記憶體池也不夠的話,則擴張之
所以,寫了一個operator new之後,要對應寫一個operator delete,因為只有自己才知道到底是如何申請記憶體的。