[CPP] new delete
前言
今天我们来谈一谈CPP中很关键的两个操作 new 和 delete ,关于他们与析构函数的关系、动态分配的内存空间、new array ( new[] ) 和 delete array ( delete[] ) 配套出现的原因以及我们可能产生误解的内存泄漏的形式。
与构造析构函数的羁绊
在一般 CPP 书中,作者都会告诉读者在调用 new 来动态创建一个对象时,会先分配空间,再调用构造函数。在调用 delete 回收空间时,会先调用析构函数,再释放内存。这里我引用第一篇攻略里的 complex 类,来深入了解其内部原理。
假设我们动态创建一个 complex 对象:
Complex *p = new Complex();
编译器会将其转化为三步:
Complex *p;
void *mem = operator new ( sizeof Complex ) ; // 1 分配内存
p = static_cast<Complex*> ( mem ) ; // 2 类型转换
p->Complex::Complex(p) ; // 3 构造函数
第一步的 operator new 就是一个函数,内部会调用malloc(sizeof Complex)分配一块内存。
第二步进行类型转换,从 void 指针转为 Complex 指针。
第三步则调用 Complex 构造函数来为内存中的两个 double 赋值。其中传进去的 p 本身就是 this 指针,指向对象自己那一片内存。

我们回收资源:
delete p;
编译器会转化为两步:
Complex::~Complex(p); // 1 析构函数
operator delete(p); // 2 释放内存
第一步调用析构函数,如果类的设计者有什么事情要在析构函数里干(比如释放成员指针指向的内存),那么就去干,没有则调用默认的析构函数。
第二步的 operator delete 同上也是一个函数,内存会调用free(p);来释放对应的内存。

内存空间初探
当我们在调用 new 和 delete 时,内存空间究竟是怎么样的,认识这一点对于我们理解 new 和 delete 是很有帮助的,但是不同的编译器提高的方案略有不同,不过大体上的思想一致,本节就以 VC++ 编译器的做法来展示,g++ 类似。
给出两个例子:


其中头尾的 cookie 表示分配的内存块的大小,注意到图里不是写错了,而是 cookie 最低的一位表示这个内存块是被分配的内存块。除此之外,分配的内存块大小必须是16的倍数,这里说的是字节,所以16就是00000011。
在 delete 的时候,就是看的 cookie 的大小来释放内存,由 cookie 来显示大小,有 cookie 来释放内存块。
delete array
我们说 new array 和 delete array 就是 new[] 和 delete[] 。我们常说 new[] 必须由 delete[] 来收回空间,否则就会造成内存泄漏。那么是怎么个泄漏法呢?
首先来看一下 new[] 的内存块:


与 new 不同的是 new[] 会多出一个 field 来表示计数器,比如上面白色的部分,不过同样需要16字节对齐。
如果使用 delete[] 来回收内存,那么需要调用 n 次析构函数,再释放内存:

但是只使用 delete ,那么只会调用 1 次析构函数,但是那一块内存同样释放了。再次提醒,内存释放需要看 cookie 大小,cookie是多大,就释放多大的空间。

因此造成内存泄漏,实际上是没有调用足够次数的析构函数。所以我们知道,对于没有指针的类,光用 delete 来释放内存是完全 OK 的,但是有指针的类,会因为没有调用析构函数造成内存泄漏。
总结
我们发现,new[] 的内存块有时候不需要 delete[] 来配套使用,但是 new delete 一起使用,new[] delete[] 一起使用是基本素养。
Reference
C++面向对象高级编程, 侯捷.
[CPP] new delete的更多相关文章
- ZT c++ 中的重载全局new,delete
c++ 中的重载全局new,delete 分类: c++ 2010-08-06 10:31 116人阅读 评论(1) 收藏 举报 deletec++file编译器语言工作 最近做一个小项目,对c++又 ...
- gperftools cpp wrapper
gperftools cpp wrapper // Compile command : ${CXX} -o test_profiler.elf -DUSE_GPERFTOOLS -DDEBUG -D_ ...
- 转:面试题:“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”
转自:http://jeromecen1021.blog.163.com/blog/static/18851527120117274624888/ 面试题目: 地球人都知道,Java有个东西叫垃圾收集 ...
- 面试题:“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”
面试题目:地球人都知道,Java有个东西叫垃圾收集器,它让创建的对象不需要像c/cpp那样delete.free掉,你能不能谈谈: GC是在什么时候,对什么东西,做了什么事情? 以上算是三个问题,下面 ...
- Android gdb 调试
[1].终端目录设置到: proj.android[2].make文件的编译选项加上: -g -gstabs+[3].执行编译脚本: sh ./build_native.sh NDK_DEBUG=1[ ...
- Java GC 面试问题
转自:http://icyfenix.iteye.com/blog/715301 这个帖子的背景是今晚看到je上这张贴:http://www.iteye.com/topic/715256,心血来潮写下 ...
- 一个资深java面试官的“面试心得”
在公司当技术面试官几年间,从应届生到工作十几年的应聘者都遇到过.先表达一下我自己对面试的观点: 1.笔试.面试去评价一个人肯定是不够准确的,了解一个人最准确的方式就是“路遥知马力,日久见人心”.通过一 ...
- SVN快速入门笔记【转】
1. SVN版本控制软件目的 协作开发 远程开发 版本回退 2. 什么是SVN subVersion 支持平台操作 支持版本回退 3. 获取SVN软件 属于C/S结构软件(客户端与服务端) serve ...
- java GC是在什么时候,对什么东西,做了什么事情
面试题:“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?” 面试题目:地球人都知道,Java有个东西叫垃圾收集器,它让创建的对象不需要像c/cpp那样delete.free掉,你 ...
随机推荐
- KVM虚拟机windows系统增加硬盘
原文:http://www.ilanni.com/?p=6211 前一篇文章介绍了有关linux系统添加硬盘的方法,这次我们来介绍有关windows系统添加的相关步骤. 其实linux和windows ...
- .net图表之ECharts随笔08-bar柱状图
之前一直都是跟着修改demo,感觉用得很吃力,现在结合上配置手册就好很多了,其实说到底就是参数的配置,所以配置手册尤为重要. 当然,这其中还是很多坑,希望可以找到对应的解决方案吧!!! 1. tool ...
- docker-compose 部署 Redis
信息: Docker版本($ docker --version):Docker版本18.06.1-ce,版本e68fc7a 系统信息($ cat /etc/centos-release):CentOS ...
- C#大数据循环
随笔 - 记录 在数据量超大的情况下使用多线程循环List,而且List不异常,一般是上锁. 不过今天发现其实内置了List的循环操作 一般情况下 用List.Foreach 数据量超大的情况下 推荐 ...
- 1、认识Struts2
先上百度百科的权威说明:一定注意我下面做标记的话: 框架就是一个半成品,就是可以帮我们完成一些业务 1. 什么是Struts2的框架 * Struts2是Struts1的下一代产品,是在 struts ...
- python单引号和双引号的区别
今天在网上爬虫的时候,很奇怪的发现python的字符串既可以用双引号又可以用单引号,于是就上网百度了一下原因. 原来由于字符串中有可能既有双引号又有单引号,例如: 字符串:demo'1'. 这时候就可 ...
- Java多线程编程 — 锁优化
阅读目录 一.尽量不要锁住方法 二.缩小同步代码块,只锁数据 三.锁中尽量不要再包含锁 四.将锁私有化,在内部管理锁 五.进行适当的锁分解 正文 并发环境下进行编程时,需要使用锁机制来同步多线程间 ...
- java中-的流-与操作
/* 字节输出流 OutputStrema: * OutputStream抽象类 * write(int b); 将指定的字节写入此流中 * write(byte[] b); ...
- SpringMvc date数据传递处理
1.form表单提交date数据 form表单提交的date数据要在接收的字段上加入@DateTimeFormat注解 @DateTimeFormat(pattern = "yyyy-MM- ...
- php 对比两个数组中的值是否相等
$a = ['1','2','4','3'];//提交答案 $b = ['2','1','3'];//正确答案 $state = $this->diffArray($b, $a); echo ' ...