/*條款52:寫了placement new 也要寫Placement delete*/
#include<iostream>
using namespace std;
//class Widget {};
class Widget {
public:
//..
static void*operator new(std::size_t size, std::ostream&logStream)throw(std::bad_alloc);//非正常形式的new
static void*operator delete(void* pMemory std::size_t size)throw();//正常的class專屬delete
// placement new :如果在operator接受的參數除了一定會有的那個size_t之外還有其他,這個便是所謂的placement new
//一個比較常用的 placement new 接受一個指針指向對象該被構造之處如下:
// void*operator new(std::size_t ,void*pMemory)throw(); 這個版本的new已被納入C++標準程序庫,頭文件#include<new>,它的用途之一是負責在vector的未使用空間上創建對象,實際上它正是這個函數的命名根據:一個特定位置的new,上下文語境往往也能夠使意義不明確的含糊話語清晰起來
//如果沒有與上面對象的operator delete 就無法對內存分配動作做恢復所以要加上下面的內容
static void operator delete (void*pMemory)throw();//如果沒有發生異常,則調用對應的delete
static void operator delete(void*pMemory, std::ostream&logStream)throw();
};//但這裏有一個名字掩蓋的問題 調用時要傳遞對應的參數,第二是子類可能有名字相同的函數把基類new掩蓋掉
/////---------------------上述出現 的掩蓋的問題可以像如下方式去解決
class StandardNewDeleteForms {
public:
//正常的new/delete
static void* operator new(std::size_t size)throw(std::bad_alloc){
return ::operator new(size);
}
static void operator delete(void* pMemory)throw() {
::operator delete(pMemory);
}
// placement new/delete
static void*operator new(std::size_t size, void*ptr)throw(){
return ::new_handler(size,ptr);
}
static void operator delete(void*pMemory, void*ptr)throw() {
return ::operator delete (pMemory, ptr);
}
//nothrow new/delete
static void*operator new (std::size_t size, const std::nothrow_t&nt)throw(){
return ::operator new(size,nt);
}
static void operator delete (void *pMemory, const std::nothrow_t &)throw() {
::operator delete(pMemory);
}
};
//凡是想以自定形式擴充標準形式的客戶,可利用繼承機制及using 聲明式取得標準形式
class Widget :public StandardNewDeleteForms {
public:
using StandardNewDeleteForms::operator new;//繼承標準形式,讓這些形式可見
using StandardNewDeleteForms::operator delete;
static void*operator new(std::size_t size, std::ostream&logStream)throw(std::bad_alloc);
static void operator delete(void*pMemory, std::ostream&logSteam)throw();//添加一個自定的placement delete
//..
};
int main() {
Widget*pw = new Widget;//這個表達式調用了兩個函數,1 operator new 2 Widget的default構造函數
//假設第一個調用成功,第二個函數卻拋出異常,那麼步驟一的內存分配所得必須取消並恢復舊觀,否則就是內存漏洞,並且客戶手上沒有指針指向被歸還的內存,取消步驟一就落到了C++運行期系統身上了
Widget *pw1 = new (std::cerr)Widget;//調用operator new 並傳遞cerr爲ostream實參,這個動作會在Widget構造函數拋出異常時泄漏內存
// 這裏的問題是如果內存分配成功,而Widget構造函數拋出異常,運行期系統有責任取消opeator new 的分配並恢復舊觀,然而運行期系統無法知道真正被調用的那個operator new 如何動作,因此無法取消分配並恢復舊觀,那麼我們可以根據上面的new找出對應的operator delete
// void operaotr(void*,std::ostream&)throw();
system("pause");
return 0;
}
條款52:寫了placement new 也要寫Placement delete
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.