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

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

1.执行析构函数。

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

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

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

看一组类定义:

#pragma once
#include<string>

struct BattleValue
{
public:
    int atk;
    int def;

    std::string name;
    std::string desc;

    BattleValue();
    ~BattleValue();
};

class Role
{
    public:
    Role();
    Role(int atk, std::string name);
    ~Role();

    Role(const Role& object);

    friend void show(Role role);

    BattleValue* data;
};

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

#include<iostream>
#include"Role.h"
using std::cout;
using std::endl;

BattleValue::BattleValue()
{
    cout<<"Battle init"<<endl;
}

BattleValue::~BattleValue()
{
    cout<<"Battle free"<<endl;
}

Role::Role()
{
    cout<<"default role"<<endl;
    data = new BattleValue();
}

Role::Role(int atk, string name)
{
    cout<<"parameter role"<<endl;
    data = new BattleValue();
    data->atk = atk;
    data->name = name;
}

Role::Role(const Role& object)
{
    cout<<"copy"<<endl;
    data = new BattleValue();
    data->atk = object.data->atk;
    data->name = object.data->name;
}

Role::~Role()
{
    cout<<"free self"<<endl;
    delete data;
}

void show(Role role)
{
    cout<<"name:"<<role.data->name<<"  atk:"<<role.data->atk<<endl;
}

int main()
{
    Role rock(, "RockDeria");
    show(rock);
    system("pause");
}

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

parameter role
Battle init
copy
Battle init
name:RockDeria  atk:
free self
Battle free
请按任意键继续. . .
free self
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. spring3种配置的比较

    引用自:Spring 3.x 企业应用开发实战

  2. YTU 3026: 中序线索化二叉树

    原文链接:https://www.dreamwings.cn/ytu3026/2896.html 3026: 中序线索化二叉树 时间限制: 1 Sec  内存限制: 128 MB 提交: 9  解决: ...

  3. Java 异常处理 练习2

    建立exception包,建立Bank类,类中有变量double  balance表示存款,Bank类的构造方法能增加存款,Bank类中有取款的发方法withDrawal(double dAmount ...

  4. grunt学习笔记

    1. 在使用grunt前需要执行的几条命令和用途 npm uninstall -g grunt  删除掉全局grunt npm install -g grunt-cli 把grunt加入你的系统搜索路 ...

  5. CSS3简单的小技巧:linear-gradient切角画册

    关于linear-gradient的语法就不多做介绍了网上到处都是,下面看个小例 我们先做一个渐变,使其让他旋转, <div class="example"> < ...

  6. GOLANG 常用命令

    golang常用命令: 命令 功能 build      编译包和依赖 run 编译并且直接运行 install 编译安装包和依赖 get 下载并安装包和依赖 fmt 调用gofmt格式化源码文件 d ...

  7. miniprofiler的对数据库的监测使用。以nancy,petapoco为例

    miniprofiler的使用 miniprofiler的详细介绍请看这里http://miniprofiler.com/.(可以对数据库和页面等监控如 ado ef mvc mongodb) 本文以 ...

  8. 小谈 checkbox 的选中

    先做草稿,稍后完善, javascript for (var i = 0; i < jsonmsg.length; i++) { var ischecked = false; for (var ...

  9. Ubuntu 修改 ssh 登录后的欢迎信息

    /etc/update-motd.d/90-updates-available cd /etc/update-motd.d/ vi 10-help-text 修改或者注释掉里面的内容 vi 90-up ...

  10. Java知识积累1-StringAlign实现文字居中左右对齐

    import java.text.*;public class StringAlign extends Format{ public static final int JUST_LEFT='l'; / ...