Effective C++第八章——定制new 和 delete
条款49——了解new-handler行为
当operator new抛出异常以反映一个未获得满足的内存需求之前,它会先调用一个客户指定的错误处理函数,叫new_handler;为了指定这个“用以处理内存不足”的函数,客户必须调用set_new_handler,该函数是一个声明于中的标准程序库函数。
namespace std{
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
}
new_handler是一个typedef定义出来的函数指针,该函数没有参数也没有返回值;set_new_handler是一个“获得一个new_handler并返回一个new_handler”的函数;set_new_handler声明式微端的“throw()”是一份异常明细,表示该函数不抛出任何异常。set_new_handler的参数是个指针,指向operator new无法分配足够内存时该被调用的函数;其返回值也是个指针,指向set_new_handler被调用前正在执行的那个new_handler函数。
例如:
//以下是当operator new 无法分配足够内存时,该被调用的函数
void outOfMen()
{
std::cerr << "Unable to satisfy request for memory\n";
std::abort();
}
int main()
{
std::set_new_handler(outOfMen);
int* pBigDataArray = new int[1000000000000L];
...
}
当operator new 无法分配足够内存时,它会不断调用new_handler函数,直到找到足够内存。
设计一个良好的new_handler函数必须做到以下事情:
- 让更多内存可被使用:程序一开始执行就分配一大块内存,而后当new_handler第一次被调用,将他们释还给程序使用。
- 安装另一个new_handler:该new_handler无法分配足够内存,则通过set_new_handler函数调用另一个能够取得更多内存的函数。
- 卸除new_handler:将null指针传给set_new_handler,一旦没有安装任何new_handler,operator new会在内存分配不成功时抛出异常。
- 抛出bad_alloc(或派生自bad_alloc)的异常:这样的异常不会被operator new捕捉,因此会被传播到内存索求出。
- 不返回:通常调用abort或exit。
请记住:
- set_new_handler 循序客户指定一个函数,在内存分配无法获得满足时被调用;
- Nothrow new 是一个颇为局限的工具,因为他自适用于内存分配;后继的构造函数的调用还是会抛出异常。
条款50——了解new和delete的合理替换时机
替换编译器提供的operator new和operator delete的理由:
- 用来检测运行上的错误;
- 为强化效能;
- 为收集使用上的统计数据;
- 为增加分配和归还的速度;
- 为了降低缺省内存管理器带来的空间额外开销;
- 为了弥补缺省分配器中的非最佳齐位;
- 为将相关对象簇集中,new和delete的“placement版本”有可能完成这样的集簇行为;
- 为获得非传统的行为
请记住:
- 有许多理由需要写个自定的new和delete,包括改善效能、对heap运用错误进行调试、收集heap使用信息。
条款51——编写new和delete时需固守常规
operator new的返回值:如果他有能力提供顾客申请的内存,就返回一个指针指向那块内存,如果没有能力,则抛出一个bad_alloc的异常。operator new实际上不止一次尝试分配内存,并在每次失败后调用new-handling函数,这里假设new-handling函数有可能释放出一些内存来,只有当new-handling函数指针指向null时才抛出bad_alloc异常。
请记住:
- operator new 应该内含一个无穷循环,并在其中尝试分配内存,如果他无法满足内存需求,就该调用new-handler。它也应该有能力处理0 bytes申请。class的专属版本则还应该处理“比正确大小更大的(错误)申请”。
- opeator delete 应该在收到null指针时不做任何事情,class的专属版本则还应该处理“比正确大小更大的(错误)申请”。
条款52——写了palcement new也要写palcement delete
正常的operator new:
void* operator new(std::size_t) throw(std::bad_alloc);
palcement new:带额外参数的new
一般提到的palcement new是指这样一个,“接受一个指针指向对象该被构造之处”。如下:
void* operator new(std::size_t, void* pMemory) throw();
与之对应的operator delete(称为palcement delete)
void operator delete(void*, std::ostream&) throw();
如果一个带额外参数的operator new没有“带相同额外参数的对应版operator delete”,那么当new的内存分配动作需要取消并恢复旧关时就没有任何operator delete调用。
请记住:
- 当你写一个 placement operator new ,请确定也写出了对应的 placement operator delete。如果没有这样做,你的程序可能会发生隐微而时断时续的内存泄露。
- 当你声明palcement new 和 palcement delete, 请确定不要无意识的(非故意)地遮掩了他们的正常版本