前言

今天我们来谈一谈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的更多相关文章

  1. ZT c++ 中的重载全局new,delete

    c++ 中的重载全局new,delete 分类: c++ 2010-08-06 10:31 116人阅读 评论(1) 收藏 举报 deletec++file编译器语言工作 最近做一个小项目,对c++又 ...

  2. gperftools cpp wrapper

    gperftools cpp wrapper // Compile command : ${CXX} -o test_profiler.elf -DUSE_GPERFTOOLS -DDEBUG -D_ ...

  3. 转:面试题:“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”

    转自:http://jeromecen1021.blog.163.com/blog/static/18851527120117274624888/ 面试题目: 地球人都知道,Java有个东西叫垃圾收集 ...

  4. 面试题:“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”

    面试题目:地球人都知道,Java有个东西叫垃圾收集器,它让创建的对象不需要像c/cpp那样delete.free掉,你能不能谈谈: GC是在什么时候,对什么东西,做了什么事情? 以上算是三个问题,下面 ...

  5. Android gdb 调试

    [1].终端目录设置到: proj.android[2].make文件的编译选项加上: -g -gstabs+[3].执行编译脚本: sh ./build_native.sh NDK_DEBUG=1[ ...

  6. Java GC 面试问题

    转自:http://icyfenix.iteye.com/blog/715301 这个帖子的背景是今晚看到je上这张贴:http://www.iteye.com/topic/715256,心血来潮写下 ...

  7. 一个资深java面试官的“面试心得”

    在公司当技术面试官几年间,从应届生到工作十几年的应聘者都遇到过.先表达一下我自己对面试的观点: 1.笔试.面试去评价一个人肯定是不够准确的,了解一个人最准确的方式就是“路遥知马力,日久见人心”.通过一 ...

  8. SVN快速入门笔记【转】

    1. SVN版本控制软件目的 协作开发 远程开发 版本回退 2. 什么是SVN subVersion 支持平台操作 支持版本回退 3. 获取SVN软件 属于C/S结构软件(客户端与服务端) serve ...

  9. java GC是在什么时候,对什么东西,做了什么事情

    面试题:“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?” 面试题目:地球人都知道,Java有个东西叫垃圾收集器,它让创建的对象不需要像c/cpp那样delete.free掉,你 ...

随机推荐

  1. DotNetBar.MetroTilePanel 样式、加载数据、获取数据

    描述下:MetroTilePanel包含子集ItemContainer  子集下面又包含子集MetroTileItem  目前我用到的就是这三层 因为需求所以整个模块全部由代码实现 1.ItemCon ...

  2. c# 前后日期设置

    List<string> list = new List<string>(); //根据当月 显示前6个月 for(int i=0;i<6;i++) { list.add ...

  3. cesium随笔 — 获取当前鼠标的经度、纬度、高度

    代码: function getPosition() { //得到当前三维场景 var scene = viewer.scene; //得到当前三维场景的椭球体 var ellipsoid = sce ...

  4. 菜鸟浅谈“诈骗”希望“治未病"

    关于目前诈骗.社工数据的套路,说道说道~ 一.前言 这篇文章没有什么高深的技术,只有普普通通的套路,主要也是有I春秋各位表哥与诈骗分子的交手有感而发! 二.正文 因为我们上网的或者其他条件下的人群,没 ...

  5. python获取aliyun ECS实例

    #!/usr/bin/env python #-*- coding:utf-8 -*- # Description : get ecs from aliyun # Author : quke # Da ...

  6. httpclient4.5 https请求 忽略身份验证

    import org.apache.commons.collections.MapUtils; import org.apache.http.*; import org.apache.http.cli ...

  7. gulp 搭建个人工作流:文件注入、热启动、跨域

    个人比价推崇前后端分离的开发方式,大家伙各司其职,只需通过 API 进行交流,不仅避免了沟通上的成本,更提升了开发效率.而在前端开发工作中,许多需求和问题是相似的,所以我们的开发模式往往是雷同的,是否 ...

  8. GraphQL 如何取代 Redux

    简评:使用 GraphQL 可以大大简化客户端状态管理部分的代码. ⚛️切换到React 故事背景:在 2016 年,Pathwright 的前端团队就开始将客户端的代码从 Backbone & ...

  9. 5. STL编程五

    1. STL的六大组件: 容器(Container) 算法(Algorithm) 迭带器(Iterator) 仿函数(Function object) 适配器(Adaptor) 空间配置器(alloc ...

  10. 回归到jquery

    最近在做一个公司的老产品的新功能,使用原来的技术框架,jquery和一堆插件,使用jquery的话,灵活性是有了,但是对于一个工作了3年多的我来说,很low,没什么成就感,技术本身比较简单,但是业务的 ...