条款八: 写operator new和operator delete时要遵循常规
自己重写operator new时(条款10解释了为什么有时要重写它),很重要的一点是函数提供的行为要和系统缺省的operator new一致。实际做起来也就是:要有正确的返回值;可用内存不够时要调用出错处理函数(见条款7);处理好0字节内存请求的情况。此外,还要避免不小心隐藏了标准形式的new,不过这是条款9的话题。
有关返回值的部分很简单。如果内存分配请求成功,就返回指向内存的指针;如果失败,则遵循条款7的规定抛出一个std::bad_alloc类型的异常。operator new实际上会不只一次地尝试着去分配内存,它要在每次失败后调用出错处理函数,还期望出错处理函数能想办法释放别处的内存。只有在指向出错处理函数的指针为空的情况下,operator new才抛出异常。
c++标准要求,即使在请求分配0字节内存时,operator new也要返回一个合法指针。
非类成员形式的operator new的伪代码看起来会象下面这样:
void * operator new(size_t size) // operator new还可能有其它参数
{ if (size == ) { // 处理0字节请求时,
size = ; // 把它当作1个字节请求来处理
}
while () {
分配size字节内存; if (分配成功)
return (指向内存的指针); // 分配不成功,找出当前出错处理函数
new_handler globalhandler = set_new_handler();
set_new_handler(globalhandler); if (globalhandler) (*globalhandler)();
else throw std::bad_alloc();
}
}
处理零字节请求的技巧在于把它作为请求一个字节来处理。
operator new经常会被子类继承,这会导致某些复杂性。大多数针对类所写的operator new(包括条款10中的那种)都是只为特定的类设计的,不是为所有的类,也不是为它所有的子类设计的。这意味着,对于一个类x的operator new来说,函数内部的行为在涉及到对象的大小时,都是精确的sizeof(x):不会大也不会小。但由于存在继承,基类中的operator new可能会被调用去为一个子类对象分配内存:
class base {
public:
static void * operator new(size_t size);
...
};
class derived: public base // derived类没有声明operator new
{ ... }; //
derived *p = new derived; // 调用base::operator new
如果base类的operator new不想费功夫专门去处理这种情况——这种情况出现的可能性不大——那最简单的办法是把这个“错误”数量的内存分配请求转给标准operator new来处理,象下面这样:
void * base::operator new(size_t size)
{
if (size != sizeof(base)) // 如果数量“错误”,让标准operator new
return ::operator new(size); // 去处理这个请求
// ... // 否则处理这个请求
}
如果想控制基于类的数组的内存分配,必须实现operator new的数组形式——operator new[]
重写operator new(和operator new[])时所有要遵循的常规就这些。对于operator delete(以及它的伙伴operator delete[]),情况更简单。所要记住的只是,c++保证删除空指针永远是安全的,所以你要充分地应用这一保证。下面是非类成员形式的operator delete的伪代码:
void operator delete(void *rawmemory)
{
if (rawmemory == ) return; //如果指针为空,返回
// 释放rawmemory指向的内存; return;
}
假设类的operator new将“错误”大小的分配请求转给::operator new,那么也必须将“错误”大小的删除请求转给::operator delete:
class base { // 和前面一样,只是这里声明了
public: // operator delete
static void * operator new(size_t size);
static void operator delete(void *rawmemory, size_t size);
...
};
void base::operator delete(void *rawmemory, size_t size)
{
if (rawmemory == ) return; // 检查空指针
if (size != sizeof(base)) { // 如果size"错误",
::operator delete(rawmemory); // 让标准operator来处理请求
return;
}
释放指向rawmemory的内存;
return;
}
条款八: 写operator new和operator delete时要遵循常规的更多相关文章
- Item 51:写new和delete时请遵循惯例
Item 51: Adhere to convention when writing new and delete. Item 50介绍了怎样自己定义new和delete但没有解释你必须遵循的惯例. ...
- 【51】编写new和delete时需固守常规
1.[50]讲了,有很多理由需要写个自定义的new/delete,自定义new/delete的时候,需要遵守一些规则. 2.循环申请,直到成功或者抛出异常,如下: void* operator new ...
- Effective C++ -----条款51:编写new 和delete 时需固守常规
operator new 应该内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存需求,就该调用new-handler.它也应该有能力处理0 bytes 申请.Class专属版本则还应该处理“比 ...
- Effective C++ 第二版 8) 写operator new 和operator delete 9) 避免隐藏标准形式的new
条款8 写operator new 和operator delete 时要遵循常规 重写operator new时, 函数提供的行为要和系统缺省的operator new一致: 1)正确的返回值; 2 ...
- 从零开始学C++之重载 operator new 和 operator delete 实现一个简单内存泄漏跟踪器
先来说下实现思路:可以实现一个Trace类,调用 operator new 的时候就将指向分配内存的指针.当前文件.当前行等信息添加进Trace 成员map容器内,在调用operator delete ...
- operator new 和 operator delete 实现一个简单内存泄漏跟踪器
先来说下实现思路:可以实现一个Trace类,调用 operator new 的时候就将指向分配内存的指针.当前文件.当前行等信息添加进Trace 成员map容器内,在调用operator delete ...
- ZT 自定义operator new与operator delete的使用(1)
http://blog.csdn.net/waken_ma/article/details/4004972 先转两篇文章: 拨开自定义operator new与operator delete的迷雾 C ...
- 类的operator new与operator delete的重载【转】
http://www.cnblogs.com/luxiaoxun/archive/2012/08/11/2633423.html 为什么有必要写自己的operator new和operator del ...
- 定制自己的new和delete:operator new 和 operator delete
new和delete不同用法 基本用法 int * aptr = new int(10); delete aptr, aptr = nullptr; 上面的代码是我们最基本也是最常见的使用new和de ...
随机推荐
- 临时笔记 Protection
如果操作系统不使用处理器的多任务机制,它仍然需要为栈创建至少一个TSS 当程序通过调用门改变特权级的时候,处理器执行下面的步骤切换栈,并且执行被调用的程序在新的特权级 1. 使用目标代码段的DPL从T ...
- adobe开发软件激活
稳定支持至2017版本系列的adobe开发软件破解激活 本内容属原创,转载请注明出处! 以激活AE CC2017为例演示: 第一步打开软件第二步在产品列表中选择你所安装的产品(注意区分 32 位和 ...
- webstorm快捷键大全-webstorm常用快捷键
默认配置下的常用快捷键,提高代码编写效率,离不开快捷键的使用,Webstorm拥有丰富的代码快速编辑功能,你可以自由配置功能快捷键. Webstorm预置了其他编辑器的快捷键配置,可以点击 查找/代替 ...
- 自动交互脚本之expect使用记录
之前一直没怎么用这个命令,意外用了一下,还不错,那这个是干嘛的呢 我们或多或少会远程登录其他服务器,需要执行某项任务,通常需要手动接入,输入密码啊,等等 那我们如何有效的自动执行呢,expect可以解 ...
- https://quotefancy.com/ 经典句子(英语) 真是特别好~
https://quotefancy.com/ 经典句子(英语)
- vue之props传值与单向数据流
(1)组件通信 父组件向子组件传递数据.这个正向传递数据的过程就是通过props来实现的. 两者区别:props中声明的数据与组件data函数return返回的数据的主要区别就是props来自父级,而 ...
- adb 设备命令
一.adb 设备命令1.查看机型时,可以使用以下命令$ adb shell getprop ro.product.model 2.如果我们忘记具体系统属性的名字$ adb shell getprop ...
- 解决java web项目导入后出现的问题 ---cannot be read or is not a valid ZIP file
导入以前的web项目后会出现以下三个错误: 1. Archive for required library: ‘WebContent/WEB-INF/lib/readme.txt’ in projec ...
- 全国绿色计算大赛 模拟赛第二阶段 (Python)
第1关气温预测 def dailyTemps(temp_list): result = [] for ca in range(0, len(temp_list)-1): for i in range( ...
- Laravel核心解读 -- 扩展用户认证系统
扩展用户认证系统 上一节我们介绍了Laravel Auth系统实现的一些细节知道了Laravel是如何应用看守器和用户提供器来进行用户认证的,但是针对我们自己开发的项目或多或少地我们都会需要在自带的看 ...