[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掉,你 ...
随机推荐
- solr特点六: DIH (从数据源导入数据)
在这个结构化数据和非结构化数据的数量都很庞大的年代,经常需要从数据库.XML/HTML 文件或其他数据源导入数据,并使数据可搜索.过去,要编写自定义代码才能创建到数据库.文件系统或 RSS 提要的自定 ...
- 遍历datatable的几种方法(C# )
转载 遍历datatable的方法2009-09-08 10:02方法一: DataTable dt = dataSet.Tables[0]; for(int i = 0 ; i ...
- .net core 2.1-----Sql Server数据库初体验
刚开始接触asp.net core,在学习的过程中遇到了一些小问题,在这里记录一下! 在我们项目的开发过程中,肯定会和数据库打交道,所以我尝试了一下用asp.net core链接数据库,并读取表中的数 ...
- Visual Studio 2013的新特性介绍
cnbeta新闻:微软正式发布Visual Studio 2013 RTM版,微软还发布了Visual Studio 2013的最终版本..NET 4.5.1以及Team Foundation Ser ...
- [UWP开发]在windows10中设置壁纸~UserProfilePersonalizationSettings
在之前的wp8.1和wp8中,微软没有公开设置壁纸的API,只有一个设置锁屏的API,但在Windows10中,微软为我们提供了设置壁纸的API:TrySetWallpaperImageAsync,他 ...
- shell脚本报错:-bash: xxx: /bin/bash^M: bad interpreter: No such file or directory
当我们把文件从windows系统中编辑的文件拷贝到linux系统中,如果我们执行文件会保存如下的错: shell脚本报错:-bash: xxx: /bin/bash^M: bad interprete ...
- 微信浏览器禁止app下载链接的两种处理方法
最近替朋友放一个微信下载链接,通过二维码扫描下载. 通过扫描二维码下载APP已成为一个非常方便的方式,微信也成为扫描二维码重要的工具,但是扫描后微信浏览器会对APK和appStore的链接进行屏蔽,导 ...
- javaweb从mysql中获取数据验证用户名密码成功跳转,失败重新验证
要求:validate.jsp页面中获取请求参数(request.getparameter(“name属性的值”)),注意中文参数获取之前要设置请求编码(request.setCharaterEnco ...
- javascript事件的类型整理
mouseenter:只能进入目标元素才会触发: mouseleave:只能离开目标元素才会触发: mouseover:进入目标元素或者其子元素的时候触发: mouseout:离开目标元素或者其子元素 ...
- ansible api2.0 多进程执行不同的playbook
自动化运维工具:ansible 多进程调用ansible api的应用场景: 应用系统检查 一个应用系统可能具有20—50台服务器的集群,初步的系统层面检查可以用一个统一的playbook来检查, ...