C++編程規範之45:總是一起提供new和delete
摘要:
它們是一攬子交易:每個類專門的重載void*operator new(parms)都必須與對應的重載void operator delete(void*, params)相隨相伴,其中parms是額外參數類型的一個列表(第一個總是std:size_t)。數組形式的new[]和delete[]也同樣如此。
很少需要提供自定義的new或者delete,但是如果需要其中一個,那麼通常兩個都需要。如果定義了類專門的T::operator new進行某種特殊的分配操作,很可能還需要定義一個類專門的T::operator delete進行相應的釋放操作。
這些闡述可能有些過於基礎了,但是之所以要加入本條款,有一個更加微妙的原因:編譯器可能需要T::operator delete的重載,即使實際上從來也不會調用它。這才是為什麼要成對提供operator new和operator delete(以及operator new[]和operator delete[])的原因。
假設定義了一個帶有自定義分配操作的類:
class T
{
//……
Static void* operator new(std::size_t)
Static void* operator new(std::size_t,CustomAllocator&)
Static void operator delete(void*,std::size_t)
};
這樣就為分配和釋放建立了一個簡單的協議。
1.調用者能夠用默認的分配器(使用new T)或者自定義的分配器,(使用new(alloc)T,其中alloc是一個customAllactor類型的對象)來分配類型T的對象。
2.唯一調用者可能調用的operatordelete是默認的operator delete(size_t),因此當然應該實現,從而能夠正確地釋放已分配的內存。
到目前為止,一切正常。
但是編譯器冉冉需要秘密地調用另一個delete重載,即T::operatordelete(size_t, CustomAllocator&)。這是因為語句
T* p = new(alloc)T;
實際上將擴展為類似下麵的代碼:
//編譯器為T* p =new(alloc)T;生成的代碼
//
Void*_compilerTemp = T::operator new (sizeof(T),alloc);
T* p;
Try
{
P = new(_compilerTemp)T;
}
Catch(…)
{
T::operator delete(_compilerTemp,sizeof(T), alloc);
throw
}
因此,如果分配成功,但是構造函數失敗了,那麼編譯器將順理成章地自動插入代碼,為重載的T::operator new調用對應的T::operator delete。對應的簽名是void operator delete(void*,whatever-parameters-new-takes).
下麵是煞風景的部分了。C++ Standard規定,當且僅當operatordelete的重載實際退出時,以上代碼才能生成。否則,在構造函數失敗的情況下,代碼不會調用任何operator delete。也就是說,如果構造函數失敗,內存將泄漏。
正因為如此,重載void*operator new(parms)必須伴有與其對應的重載void operator delete(void* ,params)——因為編譯器自己要調用它們。
最後更新:2017-04-03 12:55:09
上一篇:
openstack 命令行管理十二 - 內部網絡[instance專用]管理 (備忘)
下一篇:
C# Show()與ShowDialog()的區別
物聯網大數據與智慧農業
C語言編程 可以不會英語 但必須要懂以下英語單詞
寧夏實現“家門口”的名醫名院,智慧醫療雲平台給予更好的服務
android自定義view實現progressbar的效果
Win 8 VS OS X Mountain Lion,誰是王者?
去掉UItableview headerview黏性
oracle中報ora-01033:oracle initializationg or shutdown in progress錯
CWnd *和HWnd轉換
HTAP數據庫 PostgreSQL 場景與性能測試之 18 - (OLAP) 用戶畫像圈人場景 - 數組包含查詢與聚合
Java循環結構