Effective C++——条款51(第8章)
来源:互联网 发布:非正式会谈oo的淘宝店 编辑:程序博客网 时间:2024/06/07 06:48
条款51: 编写 new 和 delete 时需固守常规
Adhere to convention when writing new and delete.条款50已解释什么时候会想要写个自定义的 operator new 和 operator delete,但并没有解释当那么做时必须遵守什么规则.
实现一致性 opertor new 必须得返回正确的值,内存不足时必须调用 new-handling 函数(详见条款49),必须有对付零内存需求的准备,还需避免不慎遮掩正常形式的 new.
operator new 的返回值十分单纯.如果它有能力供应客户申请的内存,就返回一个指针指向那块内存.如果没有那个能力,就遵循条款49描述的规则,并抛出一个bad_alloc异常.
然而其实也不是非常单纯,因为 operator new 实际上不只一次尝试分配内存,并在每次失败后调用 new-handling函数.这里假设 new-handling函数也许能够做某些动作将某些内存释放出来.只有当指向 new-handling函数的指针使null,operator new 才会抛出异常.
C++规定,即使客户要求0 bytes,operator new 也得返回一个合法指针.这种看起诡异的行为其实是为了简化语言其他部分.下面是个non-member operator new 伪码(pseudocode):
void* operator new(std::size_t size) throw(std::bad_alloc) { using namespace std; if (size == 0) { size = 1; // 处理0-byte申请,将它视为1-byte申请 } while (true) { // 尝试分配size bytes; if (分配成功) return (一个指针,指向分配得来的内存); // 分配失败;找出目前的new-handling函数 new_handler globalHandler = set_new_handler(0); set_new_handler(globalHandler); if (globalHandler) (*globalHandler) (); else throw std::bad_alloc(); }}这里的伎俩是把0 bytes申请量视为1 bytes申请量.这种做法简单,合法,可行.
条款49谈到 operator new 内含一个无穷循环,而上述伪码明白表明这个循环:"while(true)"就是那个无穷循环.退出此循环的唯一办法就是:内存被成功分配或 new-handling函数做了一件描述于条款49的事情:让更多内存可用,安装另一个 new-handler,写出 new-handler,抛出bad_alloc异常,或承认失败而直接 return .现在,对于 new-handler为什么必须做出其中某些事情应该很清楚了,如果不那么做,operator new 内的 while 循环就永远不会结束.
operator new 成员函数可能会被derived class 继承,注意上述 operator new 伪码中,函数尝试分配size bytes.那非常合理,因为size是函数接受的实参.然而就像条款50所言,写出定制型内存管理器的一个常见理由是针对某特定 class 的对象分配行为提供最优化,却不是为了该 class 的任何derived class .也就是说针对 class X而设计的 operator new,其行为很典型地只为大小刚好为sizeof(X)的对象而设计.然而一旦被继承下去,有可能base class 的 operator new 被调用用以分配derived class 对象:
class Base {public: static void* operator new(std::size_t size) throw(std::bad_alloc); ...};class Derived : public Base{ ... };Derived* p = new Derived; // 这里调用的是Base::operator new如果Base class 专属的 operator new 并非被设计用来对付上述情况(实际上往往如此),处理此情况的最佳做法是将"内存申请量错误"的调动行为改为采取标准 operator new,像这样:
void* Base::operator new(std::size_t size) throw(std::bad_alloc) { if (size != sizeof(Base)) // 如果大小错误 return ::operator new(size); // 令标准的operator new处理 ...}operator delete 的情况更简单,需要记住的唯一事情就是C++保证"删除null指针永远安全",所以必须兑现这项保证.下面是non-member operator delete 的伪码(pseudocode):
void operator delete(void* rawMemory) throw() { if (rawMemory == 0) return ; // 如果将被删除的是个null指针,那就什么都不做 现在,归还rawMemory所指的内存;}这个函数的member版本也很简单,只需要多加一个动作检查删除数量.
注意:
operator new 应该是内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存需求,就该调用 new-handler.它也应该有能力处理0 bytes申请. class 专属版本则还应该狐狸"比正确大小更大的(错误)申请".
operator delete 应该在收到null指针时不做任何事. class 专属版本还应该处理"比正确大小更大的(错误)申请".
0 0
- Effective C++——条款51(第8章)
- Effective C++——条款8(第2章)
- Effective C++——条款49(第8章)
- Effective C++——条款50(第8章)
- Effective C++——条款52(第8章)
- Effective C++——条款10条,条款11和条款12(第2章)
- Effective C++——条款3(第1章)
- Effective C++——条款4(第1章)
- Effective C++——条款5(第2章)
- Effective C++——条款6(第2章)
- Effective C++——条款7(第2章)
- Effective C++——条款9(第2章)
- Effective C++——条款13(第3章)
- Effective C++——条款14(第3章)
- Effective C++——条款15(第3章)
- Effective C++——条款16(第3章)
- Effective C++——条款17(第3章)
- Effective C++——条款18(第4章)
- android之Service
- 没有main函数生成可执行程序的几种方法 http://www.linuxidc.com/Linux/2013-09/90061.htm
- string 与 CString 转化
- mysql常用命令
- C语言封装disruptor
- Effective C++——条款51(第8章)
- Permutations
- html点击文字显示图片
- 数组、字典转化为json字符串
- mysql 5.6 utf-8 编码设置
- hadoop集群模式下导入数据到hbase上报错
- C语言与C++中点运算符与箭头运算符的区别
- 设计模式之组合模式
- IOS:IOS9适配中出现的一些问题