都说C++内存管理是个大坑。实际上也确实是这样。

C++有析构函数,每当一个对象过期的时候,C++会执行两个动作

1.执行析构函数。

2.将对象和对象的所有数据删除。

很多人就会问了,既然有把对象删除的操作,要析构函数何用?我一开始也有一样的疑问,但是!我们都知道C++有一种神奇的类型,指针!指针他就是一个4字节的变量,甚至可以转化成int等类型打印。明白这个道理,就知道C++析构函数的作用了。

delete关键字,他后边可以接一个指针,也可以接一个例如 delete []array 这样的数组变量,其实意义都一样,它寻找的都是一个或者一组地址,把它指向的堆内存释放掉。

看一组类定义:

  1. #pragma once
  2. #include<string>
  3.  
  4. struct BattleValue
  5. {
  6. public:
  7. int atk;
  8. int def;
  9.  
  10. std::string name;
  11. std::string desc;
  12.  
  13. BattleValue();
  14. ~BattleValue();
  15. };
  16.  
  17. class Role
  18. {
  19. public:
  20. Role();
  21. Role(int atk, std::string name);
  22. ~Role();
  23.  
  24. Role(const Role& object);
  25.  
  26. friend void show(Role role);
  27.  
  28. BattleValue* data;
  29. };

这个例子中,我们看到Role类有一个变量,名字叫做data,类型是BattleValue类型的指针。其实我们在使用这个Role类的对象的时候,可以选择是否给这个data赋值一个有效值。但是有一点千万要注意,即便像构造函数中的那样给data赋值了,也不过给他赋值了一个4字节的指针变量,所以看一下源文件。

  1. #include<iostream>
  2. #include"Role.h"
  3. using std::cout;
  4. using std::endl;
  5.  
  6. BattleValue::BattleValue()
  7. {
  8. cout<<"Battle init"<<endl;
  9. }
  10.  
  11. BattleValue::~BattleValue()
  12. {
  13. cout<<"Battle free"<<endl;
  14. }
  15.  
  16. Role::Role()
  17. {
  18. cout<<"default role"<<endl;
  19. data = new BattleValue();
  20. }
  21.  
  22. Role::Role(int atk, string name)
  23. {
  24. cout<<"parameter role"<<endl;
  25. data = new BattleValue();
  26. data->atk = atk;
  27. data->name = name;
  28. }
  29.  
  30. Role::Role(const Role& object)
  31. {
  32. cout<<"copy"<<endl;
  33. data = new BattleValue();
  34. data->atk = object.data->atk;
  35. data->name = object.data->name;
  36. }
  37.  
  38. Role::~Role()
  39. {
  40. cout<<"free self"<<endl;
  41. delete data;
  42. }
  43.  
  44. void show(Role role)
  45. {
  46. cout<<"name:"<<role.data->name<<" atk:"<<role.data->atk<<endl;
  47. }
  48.  
  49. int main()
  50. {
  51. Role rock(, "RockDeria");
  52. show(rock);
  53. system("pause");
  54. }

这段代码执行后是这样的结果

  1. parameter role
  2. Battle init
  3. copy
  4. Battle init
  5. name:RockDeria atk:
  6. free self
  7. Battle free
  8. 请按任意键继续. . .
  9. free self
  10. Battle free

因为我是在windows下调试的,所以上述的结果的最后两行在cmd是几乎看不见的,一闪而过窗口就关闭了。这不影响我们来分析。

在程序开始的时候,利用参数的构造方法创建了role对象,然后在Role的构造方法中创建了一个BattleValue对象,然后我们取这个对象的地址赋值给了data变量。我们接下来调用Role类的友元函数,因为是传值参数调用,所以调用show方法的时候对role进行了复制。

复制的时候有调用了Role类的拷贝构造函数。我们在拷贝构造函数Role(const Role& object);中可以看到我们重新给data赋值,一个新的内存地址。

读到这里,想必大家都已经了解的差不多了。在对象过期的时候,是在调用析构函数之后把对象的所有数据都删除,但是*data是什么?不知道,C++只知道data,不会去解引用,只负责把这个4字节删除了。所以说,BattleValue对象的堆呢?GC何在?没有,不好意思内存就此泄漏。

所以我们才在Role的析构函数中追加了一个delete data 这样的一个操作,我们可以看到,它的作用也是两点

1.调用BattleValue类的析构函数

2.把BattleValue对象的所有数据都删除

只有这么做,我们才能做到所谓的我们想要的结果,那就是一个Role对象一个BattleValue对象,Role死BattleValue死。Role生BattleValue生。

其实这是为了方便理解,若吾早知如此,那完全可以不用这么麻烦,直接存一个BattleValue对象在Role类当中,不要放指针,这样C++会帮我们处理内存。当然,前提是需求是

一个Role对象一个BattleValue对象,Role死BattleValue死。Role生BattleValue生。但如果需求不是呢?如果所有的角色当中,弓箭手用一套战斗力,战士用一套战斗力,法师用一套战斗力。。。。。。那么你每一个角色对象都给他一个战斗力子对象对内存来说是不是太浪费了?

这个时候又该说,还是指针实在!但是内存又要如何管理了?

都说C++内存管理是个大坑。实际上也确实是这样。

C++内存管理的缩影的更多相关文章

  1. .net core中的高效动态内存管理方案

    .net core在新增的System.Buffers中引入了一大堆高效内存管理的类,如span和memory.内存池.本文今天这里介绍一个高效动态内存访问方案. ReadOnlySequenceSe ...

  2. .NET基础拾遗(1)类型语法基础和内存管理基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...

  3. PHP扩展-生命周期和内存管理

    1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...

  4. linux2.6 内存管理——逻辑地址转换为线性地址(逻辑地址、线性地址、物理地址、虚拟地址)

    Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0x00000000到0xFFFFFFFF,共4GB,但物理存储空间与虚拟存储空间布局完全不同.Linux运行在虚拟存储空间,并负责把系 ...

  5. linux2.6 内存管理——概述

    在紧接着相当长的篇幅中,都是围绕着Linux如何管理内存进行阐述,在内核中分配内存并不是一件非常容易的事情,因为在此过程中必须遵从内核特定的状态约束.linux内存管理建立在基本的分页机制基础上,在l ...

  6. Objective-C内存管理之引用计数

    初学者在学习Objective-c的时候,很容易在内存管理这一部分陷入混乱状态,很大一部分原因是没有弄清楚引用计数的原理,搞不明白对象的引用数量,这样就当然无法彻底释放对象的内存了,苹果官方文档在内存 ...

  7. Quartz2D内存管理

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px "PingFang SC"; color: #239619 } p.p2 ...

  8. 浅谈Linux内存管理机制

    经常遇到一些刚接触Linux的新手会问内存占用怎么那么多?在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在这 ...

  9. linux内存管理

    一.Linux 进程在内存中的数据结构 一个可执行程序在存储(没有调入内存)时分为代码段,数据段,未初始化数据段三部分:    1) 代码段:存放CPU执行的机器指令.通常代码区是共享的,即其它执行程 ...

随机推荐

  1. Selenium-xpath详解

    1.XPATH是什么 XPATH是一门在XML文档中查找信息的语言,XPATH可用来在XML文档中对元素和属性进行遍历,主流的浏览器都支持XPATH,因为HTML页面在DOM中表示为XHTML文档.X ...

  2. cookie 的创建 得到 删除

    //设置cookie function setCookie(attr,value,time){ if(time){ var newtime=new Date(); newtime.setTime(ne ...

  3. sql查看锁与解锁

    select request_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableName from sys.dm_tran ...

  4. java.sql.SQLException: null, message from server: "Host '192.168.xxx.xxx' is not allowed to connect to this MySQL server"

    当你连接自己的电脑上的MySQL时,报这样的错,你可以把ip换成 127.0.0.1或者localhost  ,当然前提是用户名和密码正确

  5. python之SQLAlchemy

    ORM介绍 orm英文全称object relational mapping,就是对象映射关系程序,简单来说我们类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的,为 ...

  6. 平时一些mysql小技巧及常识

    >navicat premium 快捷键1.ctrl+q 打开查询窗口2.ctrl+/ 注释sql语句3.ctrl+shift +/ 解除注释4.ctrl+r 运行查询窗口的sql语句5.ctr ...

  7. JQuery获取浏览器窗口的可视区域高度和宽度,滚动条高度

    alert($(window).height()); //浏览器时下窗口可视区域高度 alert($(document).height()); //浏览器时下窗口文档的高度 alert($(docum ...

  8. php的socket通信

    socket通常叫做'套接字',用于描述IP地址和端口,是一个通信链的句柄.应用程序通过套接字向网络发出请求或者应答忘了请求.socket既不是程序,也不是协议,其只是操作系统提供的通信层的一组抽象A ...

  9. 代码性能优化——task

    var t1 = Task.Factory.StartNew(delegate { //代码(查接口.数据库) }); 缺点: 不能使用request( HttpContext.Current.Req ...

  10. Exception in thread "main" java.lang.ExceptionInInitializerError

    Exception in thread "main" java.lang.ExceptionInInitializerErrorCaused by: java.util.Missi ...