C++内存管理的缩影
都说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++内存管理的缩影的更多相关文章
- .net core中的高效动态内存管理方案
.net core在新增的System.Buffers中引入了一大堆高效内存管理的类,如span和memory.内存池.本文今天这里介绍一个高效动态内存访问方案. ReadOnlySequenceSe ...
- .NET基础拾遗(1)类型语法基础和内存管理基础
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...
- PHP扩展-生命周期和内存管理
1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...
- linux2.6 内存管理——逻辑地址转换为线性地址(逻辑地址、线性地址、物理地址、虚拟地址)
Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0x00000000到0xFFFFFFFF,共4GB,但物理存储空间与虚拟存储空间布局完全不同.Linux运行在虚拟存储空间,并负责把系 ...
- linux2.6 内存管理——概述
在紧接着相当长的篇幅中,都是围绕着Linux如何管理内存进行阐述,在内核中分配内存并不是一件非常容易的事情,因为在此过程中必须遵从内核特定的状态约束.linux内存管理建立在基本的分页机制基础上,在l ...
- Objective-C内存管理之引用计数
初学者在学习Objective-c的时候,很容易在内存管理这一部分陷入混乱状态,很大一部分原因是没有弄清楚引用计数的原理,搞不明白对象的引用数量,这样就当然无法彻底释放对象的内存了,苹果官方文档在内存 ...
- Quartz2D内存管理
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px "PingFang SC"; color: #239619 } p.p2 ...
- 浅谈Linux内存管理机制
经常遇到一些刚接触Linux的新手会问内存占用怎么那么多?在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在这 ...
- linux内存管理
一.Linux 进程在内存中的数据结构 一个可执行程序在存储(没有调入内存)时分为代码段,数据段,未初始化数据段三部分: 1) 代码段:存放CPU执行的机器指令.通常代码区是共享的,即其它执行程 ...
随机推荐
- 剑指offer——树的子结构 (JAVA代码)
版权声明:本文为博主原创文章,未经博主允许不得转载. 题目描述: 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构). 解题思路: 首先看牛客网给出的测试用例: ...
- android中webrtc的几个关键的状态
在android层使用webrtc的时候,都是通过native层回调的形式来触发ui的改变,比如在什么时候绘出对方的视频窗口,什么时候表示双方连接已经建立等等... 我现在把我知道的列出来用于备忘. ...
- 开发工具&环境
远程拷贝:scp cdh4.tar.gz root@10.239.44.111 ~ gerrit for code review: git add . git commit -a git push o ...
- nodejs路由的部分通配
1. 占位标识符/:id app.get('/post_api_post_data_ren/bet/follow/:gameEn',function(req,res){ console.log(req ...
- API Monitor v2.0 Alpha-r13 (32+64) 汉化版
API Monitor v2.0 Alpha-r13 (32+64) 汉化版: 链接: https://pan.baidu.com/s/1jIx5znC 密码: 4538 本软件已最大化汉化,已经趋于 ...
- EXCEL表格实现万位分隔符效果!
单击单元格右键 选择自定义单元格格式 选择数字标签 选择自定义 在输入框中输入:###","#### 单击确定即可! 格式刷可以对其他单元格实行同样效果!
- [OC] 图片平铺
Tip: self.bgImg.image = [self.bgImg.image resizableImageWithCapInsets:UIEdgeInsetsMake(100, 40, 40, ...
- Building Websites in ASP.NET
ASP.NET offers three frameworks for creating web applications: Web Forms, ASP.NET MVC, and ASP.NET W ...
- 调度系统任务创建---创建一个JoinTrigger的依赖任务(五)
有时候我们需要创建一个任务,这个任务有多个下游任务,在所有下游任务执行成功后再触发一个join操作. 这种场景可以使用JoinTrigger的触发器来实现. 该场景对应的拓扑结构如下: 该触发器的详细 ...
- 插件开发-UI插件开发
1.新建类库解决方案,引入命名空间,同时引入要添加UI Form的WebPart(在Portal\UILib目录下) 2.继续UFSoft.UBF.UI.Custom.ExtendedPartBase ...