第八章 定制new和delete

对于程序开发来说,了解C++内存管理例程的行为是非常重要的。其中两个主角是分配例程和归还例程(operator newoperator delete),配角是new-handker,这是当operator new无法满足客户的内存需求时所调用的函数。

注意STL容器所使用的heap内存是由容器所拥有的分配器对象(allocator objects)管理,不是被newdelete直接管理。

条款49:了解new-hander的行为

请记住

  • set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用。
  • Nothrow new是一个颇为局限的工具,因为它只适用于内存分配;后继的构造函数调用还是可能抛出异常。

条款50:了解newdelete的合理替换机制

一般处于下列原因可能想要替换编译器提供的operator newoperator delete

  • 为了检测运用错误。
  • 为了收集动态分配内存的使用统计信息。
  • 为了增加分配和归还的速度。
  • 为了降低缺省内存管理器带来的空间额外开销。
  • 为了弥补缺省分配器中的非最佳齐位。
  • 为了将相关对象成簇集中。
  • 为了获得非传统的行为。

下面是一个”为了检测运用错误“而实现的简单的 operator new 的例子,通过在首部和尾部插入一个签名,返回中间内存块给程序使用,如果程序在使用内存时发生过在区块前或区块后写入的行为,那么签名就会被修改,因此可以检测这种行为:

static const int signature = 0xDEADBEEF; // 边界符
typedef unsigned char Byte;
void* operator new(std::size_t size) throw(std::bad_alloc) {
// 多申请一些内存来存放占位符
size_t realSize = size + 2 * sizeof(int);
// 申请内存
void *pMem = malloc(realSize);
if (!pMem) throw bad_alloc();
// 写入边界符
*(reinterpret_cast<int*>(static_cast<Byte*>(pMem)+realSize-sizeof(int)))= *(static_cast<int*>(pMem)) = signature;
// 返回真正的内存区域
return static_cast<Byte*>(pMem) + sizeof(int);
}

这个例子主要是展示,它存在很多错误:

  • 所有的 operator new 都应该内含一个循环,反复调用某个 new-handling 函数,这里却没有。
  • C++要求所有 operator new 返回的指针都有适当的对齐。这里 malloc 返回的指针是满足要求的,但是因为上述实现并不是直接返回 malloc 的结果,而是返回一个 int 偏移后的地址,因此无法保证它的安全。

请记住

  • 有许多理由需要自定的newdelete,包括改善效能、对heap运用错误进行调试、手机heap使用信息。

条款51:编写newdelete时需固守常规

请记住

  • operator new应该包含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存要求,就该调用new-handler。它也应该有能力处理0bytes申请。Class专属版本则还应该处理"比正确大小更大的(错误)申请"。
  • operator delete应该在收到null指针时不做任何事。Class专属版本则还应该处理"比正确大小更大的(错误)申请"。

条款52:写了placement new也要写placement delete

请记住

  • 当你写一个placement operator new,请确定也写出类对应的placement operator delete。如果没有这样做,你的程序可能会发生隐蔽而时断时续的内存泄漏。
  • 当你声明placement newplacement delete,请确定不要无意识(非故意)地遮掩了它们的正常版本。

【C++】《Effective C++》第八章的更多相关文章

  1. 【C++】《C++ Primer 》第十八章

    第十八章 用于大型程序的工具 大规模应用程序的特殊要求包括: 在独立开发的子系统之间协同处理错误的能力. 使用各种库进行协同开发的能力. 对比较复杂的应用概念建模的能力. 一.异常处理 异常处理(ex ...

  2. c++ primer plus(文章6版本)中国版 编程练习答案第八章

    编程练习答案第八章 8.1写输出字符串的函数,存在默认参数表示输出频率,莫感觉1.(原标题太扯了,的问题的细微变化的基础上,含义) //8.1编写一个输出字符串的函数.有一个默认參数表示输出次数,默觉 ...

  3. C++ Primer Plus学习:第八章

    C++入门第八章:函数探幽 本章将介绍C++语言区别于C语言的新特性.包括内联函数.按引用传递变量.默认的参数值.函数重载以及函数模板. 1 C++内联函数 内联函数是C++为提高程序运行速度所做的一 ...

  4. 【C++】《C++ Primer 》第八章

    第八章 IO库 一.IO类 1. 标准库定义的IO类型 头文件 作用 类型 iostream 从标准流中读写数据 istream, wistream 从流读取数据 ostream, wostream ...

  5. C++Primer 第十八章

    //1.异常:待研究 //2.命名空间: // A:多个库将名字放置在全局命名空间中将引发命名空间污染. // B:命名空间为防止名字冲突提供了更加可控的机制.命名空间分割了全局命名空间,其中每个命名 ...

  6. C++ Primer:第八章:IO库(续)

    二:文件输入输出. (1) 使用文件流对象: 头文件fstream定义了三个类型来支持文件IO:ifstream从一个给定的文件中读取数据,ofstream向一个给定的文件中写入数据,以及fstrea ...

  7. C primer plus 读书笔记第八章

    本章的标题是字符输入/输出和输入确认.主要内容是讨论用于I/O的标准函数. 1.getchar()和putchar() 这两个函数之前用过,我们通过这两个函数来讨论下缓冲区. #include &qu ...

  8. C++ primer 中文第三版 阅读笔记 第八章

    一.寄存器对象: 函数中频繁被使用的变量可以加上register就可声明为寄存器对象.对于寄存器对象,假如能够放到寄存器中就会放到寄存器中,放不到的话就放到内存中.比如 register int  a ...

  9. C++ Primer的课后规划问题的第八章

    1.写通常需要一个参数(字符串的地址).字符串和打印功能. 只要.假设提供了第二个参数(int种类),而这个参数不0,的次数的函数打印串数量为该功能将被称为(意,字符串的打印次数不等于第二个參数的值. ...

  10. c primer plus(五版)编程练习-第八章编程练习

    1.设计一个程序,统计从输入到文件结尾为止的字符数. #include<stdio.h> int main(void){ int ch; int i; i=; while((ch = ge ...

随机推荐

  1. STL——容器(Map & multimap)的查找

    map.find(key);   //查找键key是否存在,若存在,返回该键的元素的迭代器:若不存在,返回map.end(); map.count(key);   //返回容器中键值为key的对组个数 ...

  2. C++ 虚函数表与多态 —— 多态的简单用法

    首先看下边的代码,先创建一个父类,然后在来一个继承父类的子类,两个类中都有自己的 play() 方法,在代码的第35-37行,创建一个父类指针,然后将子类地址引用赋值给父类,这时调用 P 指针的 pl ...

  3. Mysql常用函数合集

    1. 字符函数 length(获取字节数,UTF-8编码中 一个汉字占3个字节,GBK编码中一个汉字占2个字节) select length('abc'); #结果:3 select length(' ...

  4. RocketMQ集群搭建(3m-3s-async)

    RocketMQ集群搭建(3m-3s-async) 各角色介绍 角色 作用 Producer 消息发送者,将消息发送到 Broker.无状态,其与NameServer集群中的一个节点建立长连接,定期从 ...

  5. Oracle 常用语句1

    -- 我是注释信息 sql语句 -- 创建用户: create user 用户名 identified by 密码; create user jack identified by j123; -- l ...

  6. C#中的深度学习(二):预处理识别硬币的数据集

    在文章中,我们将对输入到机器学习模型中的数据集进行预处理. 这里我们将对一个硬币数据集进行预处理,以便以后在监督学习模型中进行训练.在机器学习中预处理数据集通常涉及以下任务: 清理数据--通过对周围数 ...

  7. Codis集群相关

    在大数据高并发场景下,单个 Redis 实例往往会显得捉襟见肘.首先体现在内存上,单个 Redis 的内存不宜过大,内存太大会导致 rdb 文件过大,进一步导致主从同步时全量同步时间过长,在实例重启恢 ...

  8. Django项目连接多个数据库配置

    1.设置数据库连接 pip install PyMySQL 2.在项目同名目录myproject/myproject下的__init__.py添加以下代码 import pymysql pymysql ...

  9. 装逼篇 | 抖音超火的九宫格视频是如何生成的,Python 告诉你答案

    1. 场景 如果你经常刷抖音和微信朋友圈,一定发现了最近九宫格短视频很火! 从朋友圈九宫格图片,到九宫格视频,相比传统的图片视频,前者似乎更有个性和逼格 除了传统的剪辑软件可以实现,是否有其他更加快捷 ...

  10. python归并排序

    由于某人问我要个归并排序,就凑合写了一个,AA = raw_input().split(' ') A = []; for num in AA: A.append(int(num)) def Merge ...