《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,找不到调用不了,会造成资源泄漏
posted @ 2019-01-08 15:45  narjaja  阅读(221)  评论(0编辑  收藏  举报