热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

EffectiveC++条款51:编写new和delete时需固守常规

(一)实现一致性operatornew必须返回正确的值,内存不足时必须调用new_handling函数,必须有对付零内存的准备,还需要避免不慎掩盖正常形式的new。vo

(一)

实现一致性operator new必须返回正确的值,内存不足时必须调用new_handling函数,必须有对付零内存的准备,还需要避免不慎掩盖正常形式的new。

void* operator new(std::size_t size) throw(std::bad_alloc) { 
    using namespace std; 
    if (size == 0) { 
        size = 1; 
    } 
    while (true) { 
        尝试分配size byte 
        if (分配成功) 
            return (一个指针,指向分配得来的内存) 
        // 分配失败 
        new_handler globalHandler = set_new_handler(0); 
        set_new_handler(globalHandler);

        if (globalHandler) (*globalHandler)(); 
        else throw std::bad_alloc(); 
    } 
}
没有任何办法直接取得new_handling函数指针,所以必须调用set_new_handler找它出来。拙略,但有效——至少对单线程程序而言,多线程或许需要某种机锁以便安全处置new_handling函数背后的global数据结构。

operator new有个无穷循环,退出次循环的唯一办法是:内存成功分配或new_handling函数做了一件描述于条款49的事情:让更多内存可用、安装另一个new_handler、卸除new-handler、抛出bad_alloc异常、或者承认失败而直接return。


(二)

operator new成员函数会被derived classes继承。如果针对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); 
    ... 
}
如果size 为0,这份申请转交到::operator new手上,因为sizeof(Base)的大小不可能为0。

如果打算控制class专属“array内存分配行为”,那么你要实现operator new的array兄弟版;operator new[]。通常被称为“array new”,如果决定写个operator new[],唯一要做的一件事就是分配一块未加工内存,因为你无法对array之内迄今尚未存在的元素对象做任何事情。实际上,你甚至无法计算那个array将含多少个元素对象。你不知道每个对象多大,毕竟base class的operator new[]有可能经由继承被调用,将内存分配给“元素为derived class对象”的array使用。

因此,你不能在Base::operator new[] 内假设array的每个元素对象的大小是sizeof(base),这也意味着你不能假设array的元素个数是(byte申请数)/sizeof(base)。此外,传递给operator new[]的size_t参数,其值有可能比“将被填以对象”的内存数量多,条款16说过,动态分配的arrays可能包含额外空间用来存放元素个数。


(三)

operator delete的情况更简单,只要记住唯一的事情就是C++保证删除null指针永远安全,所以你必须兑现这项保证。

下面是non-member operator delete的伪码:

void operator delete(void *rawMemory) throw() { 
    if (rawMemory == 0) return; 
    现在,归还rawMemory所指内存 
}

下面是member operator delete,member版本也简单,只需多加一个动作检查删除数量。

万一你的class专属operator new将大小有误的分配转交::operator new执行,你必须也将大小有误的删除行为转交::operator delete执行:

class Base {
public:
	static void* operator new(std::size_t size) throw(std::bad_alloc);
	static void operator delete(void* rawMemory, std::size_t size) throw();
};

void Base::operator delete(void* rawMemory, std::size_t size) throw() {
	if(rawMemory == 0) return 0;
	if(size != sizeof(Base)) {
		::operator delete(rawMemory);	
		return;
	}
	现在,归还rawMemory所指的内存;
	return ;
}
如果即将被删除的对象派生自某个base class而后者欠缺virtual析构函数,那么c++传给operator delete的size_t数值可能不正确。

此时,operator delete可能无法正确运作。


请记住:

(1)operator new应该内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存需求,就该调用new-handler。它也应该有能力处理0bytes申请,class专属版本则还应该处理“比正确大小更大的(错误)申请”。

(2) operator delete应该在收到null指针时不做任何事情。class专属版本则还应该处理“比正确大小更大的(错误)申请”。









Effective C++ 条款 51:编写new和delete时需固守常规


推荐阅读
  • PDF内容编辑的两种小方法,你知道怎么操作吗?
    本文介绍了两种PDF内容编辑的方法:迅捷PDF编辑器和Adobe Acrobat DC。使用迅捷PDF编辑器,用户可以通过选择需要更改的文字内容并设置字体形式、大小和颜色来编辑PDF文件。而使用Adobe Acrobat DC,则可以通过在软件中点击编辑来编辑PDF文件。PDF文件的编辑可以帮助办公人员进行文件内容的修改和定制。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 本文介绍了一种解析GRE报文长度的方法,通过分析GRE报文头中的标志位来计算报文长度。具体实现步骤包括获取GRE报文头指针、提取标志位、计算报文长度等。该方法可以帮助用户准确地获取GRE报文的长度信息。 ... [详细]
author-avatar
炙天痕_953
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有