《Effective C++》定製new和delete:條款49-條款52
阿新 • • 發佈:2019-01-08
條款49:瞭解new-handler的行為
- 當operator new無法分配出記憶體會丟擲異常std::bad_alloc
- 丟擲異常前會反覆呼叫使用者自定義的new-handler函式直至成功分配記憶體
// 自定義new_handler函式 void outOfMem() { cerr << "Unable to satisfy request for memory" << endl; abort(); } //測試 int main() { set_new_handler(outOfMem); //寫入new_handler函式 int* pBigDataArray = new int[100000000000000000L]; return 0; } //輸出 :Unable to satisfy request for memory //聲明於<new>中的標準程式函式 namespace std { typedef void (*new_handler) (); new_handler set_new_handler(new_handler p) throw(); }
- 為不同的class寫不同的new-handler函式
#include <stdio.h> #include <iostream> #include <vector> using namespace std; class NewHandlerHolder { public: explicit NewHandlerHolder(new_handler nh) : handler(nh) {} ~NewHandlerHolder() {std::set_new_handler(handler);} private: new_handler handler; NewHandlerHolder(const NewHandlerHolder&) {} NewHandlerHolder& operator= (const NewHandlerHolder&) {} }; template<typename T> class NewHandlerSupport { public: static new_handler set_new_handler(new_handler p) throw(); static void* operator new[](size_t size) throw(bad_alloc); private: static new_handler currentHandler; }; template<typename T> new_handler NewHandlerSupport<T>::currentHandler = 0; template<typename T> new_handler NewHandlerSupport<T>::set_new_handler(new_handler p) throw() { new_handler oldHandler = currentHandler; currentHandler = p; return oldHandler; } template<typename T> void* NewHandlerSupport<T>::operator new[](size_t size) throw(bad_alloc) { NewHandlerHolder h(std::set_new_handler(currentHandler)); return ::operator new[](size); } class Widget : public NewHandlerSupport<Widget>{ }; void outOfMem() { cerr << "Unable to satisfy request for memory" << endl; abort(); } int main() { Widget::set_new_handler(outOfMem); Widget* pwl = new Widget[100000000000L]; return 0; }
條款50:瞭解new和delete的合理替換時機
- 有許多理由需要自定new和delete,包括改善效能、對heap運用錯誤進行除錯、手機heap使用資訊
條款51:編寫new和delete時需固守常規
- operator new 應該包含一個無窮迴圈,並在其中嘗試分配記憶體,如果無法滿足記憶體需求,就呼叫new-handler函式,且要有能力處理 0 bytes申請。
- operator delete應該在收到null指標時不做任何事情
條款52:寫了placement new也要寫placement delete
- 當寫new的表示式\(Widget* pw = new Widget\)
- 一個是用以分配記憶體的 operator new
- 另一個是Widget的default建構函式
- 如果在呼叫建構函式失敗,編譯器會尋找一個“帶相同額外引數”的operator delete,找不到調用不了,會造成資源洩漏