● 通用概念
Widget *pw = new Widget;
其實分為兩步:
1> 調用operator new分配記憶體
2> 調用ctor初始化對象
如果第2步拋出異常,系統會自動調用
1> void operator delete(void *mem) throw();
2> void Widget::operator delete(void *mem, std::size_t size) throw();
二者之一來回收記憶體。
系統尋找和new對應的delete時是一一對應。如果對於一個placement new沒有給出placement delete,則無法回收記憶體。
所以,自訂new/delete時要保持一一對應:
class Widget {<br />public:<br />static void* operator new(std::size_t size, std::ostream& log) throw(std::bad_alloc);<br />static void operator delete(void *pMemory, std::ostream& log) throw();<br />...<br />};<br />Widget *pw = new (std::cerr) Widget;
此時若出現異常,系統會自動找到帶ostream的delete。
● STL中有一個placement new:
void* operator new(std::size_t, void *pMemory) throw();
該函數用於vector在內部給新對象尋找儲存位置。placement new因此而得名。placement是名詞“安置、尋找合適位置”的意思。
現在一般意義上,只要帶有多餘參數的new都叫placement new。系統在匹配placement new和placement delete時,也是靠比較那些多餘的參數而完成的。
● Item 33講了類在派生的時候,如果重名就會發生定義遮擋的問題:
class Base {<br />public:<br />static void* operator new(std::size_t size, std::ostream& log) throw(std::bad_alloc);<br />...<br />};<br />Base *pb = new Base; // 錯誤!預設的new被遮擋了<br />Base *pb = new (std::cerr) Base; // 正確<br />class Derived: public Base {<br />public:<br />// 這個厲害,把基類的也給擋了<br />static void* operator new(std::size_t size) throw(std::bad_alloc);<br />...<br />};<br />Derived *pd = new (std::clog) Derived; // 錯誤<br />Derived *pd = new Derived; // OK
先要瞭解C++預定義的new:
void* operator new(std::size_t) throw(std::bad_alloc); // normal new<br />void* operator new(std::size_t, void*) throw(); // placement new<br />void* operator new(std::size_t, const std::nothrow_t&) throw(); // no-throw new
這些都是你要在你的類裡重定義的。
簡單做法如下:
class StandardNewDeleteForms {<br />public:<br />// normal new/delete<br />static void* operator new(std::size_t size) throw(std::bad_alloc)<br />{ return ::operator new(size); }<br />static void operator delete(void *pMemory) throw()<br />{ ::operator delete(pMemory); }<br />// placement new/delete<br />static void* operator new(std::size_t size, void *ptr) throw()<br />{ return ::operator new(size, ptr); }<br />static void operator delete(void *pMemory, void *ptr) throw()<br />{ return ::operator delete(pMemory, ptr); }<br />// nothrow new/delete<br />static void* operator new(std::size_t size, const std::nothrow_t& nt) throw()<br />{ return ::operator new(size, nt); }<br />static void operator delete(void *pMemory, const std::nothrow_t&) throw()<br />{ ::operator delete(pMemory); }<br />};<br />// 誰想自訂new,就要從StandardNewDeleteForms裡派生<br />class Widget: public StandardNewDeleteForms {<br />public:<br />// 然後用using聲明一下標準的<br />using StandardNewDeleteForms::operator new;<br />using StandardNewDeleteForms::operator delete;<br />// 最後定義自己的<br />static void* operator new(std::size_t size, std::ostream& log) throw(std::bad_alloc);<br />static void operator delete(void *pMemory, std::ostream& log) throw();<br />...<br />};