1. 程式人生 > >《Effective C++》定製new和delete:條款49-條款52

《Effective C++》定製new和delete:條款49-條款52

條款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,找不到調用不了,會造成資源洩漏