• 欢迎来到GeekFaner

    每周更新一篇教程,轻松学习cocos2d-x

    联系我们
  • 又是一个美好的一天

    每天的太阳都是新的,今天要比昨天好

    联系我们
  • 出发!

    开始今天的课程学习,让我们的明天更美好

    联系我们

课程概述

“Cocos2d-x 引擎源码中的数据类型”课程概述

上一讲介绍了Cocos2d-X的内存管理理论(使用引用计数和AutoReleasePool“智能指针”),所有的UI元素基本都使用到了这两个理论,使用方法在上一节的视频中也有了一定的介绍。本节主要讲述非UI元素,且也会用到内存的基本数据结构,如何进行内存管理。

教学视频

课程笔记

Vector

Vector是3.x系列之后提出来的新的数据结构,综合了std::vector有很多函数,可以很方便的进行很多数据操作,也融入了Cocos2d-X的内存管理。

Vector区别于普通的类型sprite等,Vector是用于存储一组数据的容器,顾名思义也就理应当管理一大块内存。比如可以将5个sprite都放入一个vector,那么vector要对这5个sprite进行内存管理,也要具备可以很方便有效的对这些数据进行插入、删除、搜索等处理。

为了实现对这5个sprite的内存管理,Vector采用了Cocos2d-X引用计数和智能指针的理念。首先,Vector本身是局部变量,不占用堆里的内存,这样Vector的生命周期受作用域的控制,在Vector的析构函数中进行内存释放,然后,传入的变量必须是Ref的子集,这样才能使用引用计数retain和release函数,在将这些变量往Vector进行操作的时候进行内存管理。比如在copy、pushBack、insert、replace的时候对元素进行retain,在popback、erase、clear、replace对元素进行release,在swap、move不对元素进行内存管理

为了方便有效的对这些数据进行操作,Vector本身就是一个std::vector,然后包装了std::vector的begin、end、capacity、size、empty、max_size、getIndex、front、back、shrinkToFit等方法,还自己提供了一些自定义方法replace、swap、find等

map

Map类似于Vector,包装了std::unordered_map和std::map,并且也融入了Cocos2d-X的内存管理。

unordered_map是将key转化成了hash,然后按照hash的顺序来进行存储,并非按照key或者value的顺序来存储。当进行搜索的时候,将key转化成hash进行搜索,算法复杂度最快是o(1),最慢是o(n)。unordered_map的hash算法是根据一个固定值buckets来计算,所以在初期的时候会设定一个buckets值,这个值相当于reserve的capacity,如果Map中存放的元素数量超过buckets就需要重新计算hash值,所以需要根据插入元素的频繁度和数量进行权衡,决定创建的时候设定reserve的capacity。另外这个hash算法是将key转化为hash值,但如果key为int,那么用key来当作hash值。

Map和Vector的另外一个关系是:Map的value相当于Vector的元素,在内存管理的过程中Vector会将元素进行retain和release,则Map对value进行retain和release,也就是iter->second。

Value

Vector、Map都是容器,而Value相当于Int、Float、Vector等所有数据结构的包装体,所有数据都可以定义成Value类型,然后通过Value提供的方法进行数据类型转换,通过Value的析构函数来进行内存管理。

Value的构造函数传入一个参数,这个参数用于给这个Value进行赋值,并确定Value的数据类型。假如传入参数为int,那么Value就是int类型的数据,假如传入参数为std::vector,那么会new一块vector,然后赋值。然而Value是局部函数,在生命周期结束的时候,调用析构函数,将new的这一块vector进行delete。在赋值操作的时候,如果Value本身的数据类型与参数数据类型不符合,假如之前的是std::vector,新的参数为td::unordered_map。那么会先将之前的进行delete,然后new一块新的内存。如果是move操作,则只需要将先用的进行clear,然后直接将参数的move过来,再将参数的type设置为none即可。在做数据类型转换的时候,如果可以转换的就转化,如果不可以转换的就转换为0。

RefPtr

特点

经过上面几节课的学习,我们知道Cocos2d-X的内存管理可以交给AutoReleasePool、Vector、Map进行管理,然后这三个都是容器的概念,Cocos2d-X的元素是否可以自己管理自己的内存呢?答案是可以的,那么就是RefPtr,Cocos2d-X中一种类似shared_ptr指针的智能指针。该指针对一个Ref*保持强引用,然而在RefPtr包装的函数中,也通过Cocos2d-X中Ref的retain和release对Ref*进行内存管理。

RefPtr借用了shared_ptr的理念,实现和shared_ptr基本完全一样的功能,但是没有进行线程保护,这样也就避免了性能的损失。

RefPtr的构造函数会对所有非NULL的对象进行retain。如果传入参数为右值,那么就不进行retain。

RefPtr的赋值操作符会将之前的对象进行release,对参数中新传入的对象进行retain。如果传入参数为右值,那么就不进行retain。

RefPtr的bool函数用于返回RefPtr是否为null。

RefPtr的reset函数用于将对象release。

RefPtr的swap函数用于将自己的对象和参数的对象进行交换,引用计数不变。

RefPtr的weakAssign函数将自己的对象release,然后指向参数的对象。

RefPtr可以通过*或者get函数直接拿到对象的地址,拿到的地址即使Ref*,这个Ref*可以再加入Vector、Map等进行内存管理。

缺陷

RefPtr封装的Ref*对象可以自己进行retain和release函数,这样会导致很多不确定性。比如Ref*自己执行了release函数,那么在RefPtr运行析构函数的时候,就会出错。

RefPtr仍然可以对其weakAssign方法得到的Ref*对象进行retain、release操作,如果进行了release操作,导致Ref被释放,那么在原智能指针处,如果使用这块内存,就会出错。

联系我们

笔者制作网站的目的,主要是借用自己之前的知识背景(Android App开发和图形学知识),将自己学习笔记拿出来,和大家一起进行交流,毕竟每个人的知识体系不同,有交流才会有提高,所以欢迎大家通过各种方式和我联系。
网址:www.geekfaner.com
"极客学院"教学视频(高清版_推荐):http://www.jikexueyuan.com/course/cocos/1-5-0/

wangshuo@geekfaner.com