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