《Effective C++》定制new和delete:条款49-条款52

时间:2023-01-22 15:18:40

条款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,找不到调用不了,会造成资源泄漏