條款52:寫了placement new 也要寫Placement delete

/*條款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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章