Cocos2dx 3.4内存管理机制——RefPtr
—简介:2dx3.1引入了智能指针RefPtr<T>,RefPtr<T>是基于RAII实现的,在RAII中,动态资源的持有发生在一个对象的生命周期之内,也就是在对象的构造函数中分配内存,对象的析构函数中释放内存,这样做也就是把动态内存与自动变量进行绑定,通过自动变量的构造与析构函数来管理动态内存,这也就是各种智能指针的基本原理。 —特点:1、模仿C++11的std::shared_ptr实现 2、无法保证线程的安全 3、更加轻量级 —用处:用于管理游戏中数据的内存 游戏中的数据,例如__String,或者自定义的某个数据类 2dx中明明已经有autorelease的内存管理方法了,为何还要添加RefPtr<T>? 因为数据对象创建后,调用了autorelease方法,若数据对象未被引用,则会在每一帧结束后被释放,对于需要经常调用的数据,这显然是我们不想要见到的,那么有什么方法可以解决呢? 一、直接retain,不要时release,这种方法显然不好,要不2dx的内存管理直接用C++ 的new、delete就好了。 二、将其添加至某个节点下作为子节点,我最初认为这种方法应该是不错的了,但是后 来想了一想,首先,想成为子节点,自身就必须继承自Node,而简单的数据对 象并不需要Node的特性,因此也不是十分理想 通过上述叙述,2dx中现有的autorelease方法显然不适用于游戏中数据的管理,但是对于游戏中的UI元素来说,还是十分好的。 —RefPtr<T>的工作流程简析 RefPtr<__String>ref2(String::create(“Hello”)); 上述语句可分为三部分来看,首先数据类型RefPtr<__String>,表示智能指针指向的内存是__String类型的;其次String::create(“Hello”),构造函数的参数,返回__String对象,最后ref2(String::create(“Hello”)),RefPtr<__String>对象的创建,调用了RefPtr<__String>的构造函数,在构造函数中,首先将String::create(“Hello”)赋值给RefPtr<T>中的Ref对象_ptr,接着再对_ptr进行retain();这样智能指针的创建过程就完成了。 在游戏的运行过程中,第一帧结束后,_ptr便release一次了,因此此时_ptr的引用计数为1,当ref2对象析构时,会对_ptr进行release,并把_ptr置空,此时动态分配的数据便被释放了。 当然在游戏的运行过程中,数据对象可能需要被其他类进行引用,因此数据对象也是需要拷贝的,智能指针在这方面与引用计数有些相似,拷贝一次引用计数加一,这也是为什么智能指针指向的数据类型只能是继承自Ref的原因了。 —部分源码解析: 1、//模板类,T可以是任意继承自Ref的类型,否则无法对引用计数进行操作 template<typenameT>classRefPtr { } 2、//空构造函数,让智能指针指空 inlineRefPtr() : _ptr(nullptr) { } 3、//转移构造函数(自己命名的,后续类似),当形参为智能指针的左值时,意味着内存的管理是被转移而不是被共享 inlineRefPtr(RefPtr<T>&&other) { _ptr=other._ptr; other._ptr=nullptr; } 4、//转换构造函数(自己命名的,后续类似),将T*类型的变量转换为RefPtr<T>类型的,同时对_ptr进行retain操作 inlineRefPtr(T*ptr) : _ptr(const_cast<typenamestd::remove_const<T>::type*>(ptr)) { CC_REF_PTR_SAFE_RETAIN(_ptr); } 5、 //共享构造函数(自己命名的,后续类似),当形参为智能指针的右值时,意味着内存的被另一个RefPtr<T>所共享,改内存的引用计数加一 inlineRefPtr(constRefPtr<T>&other) : _ptr(other._ptr) { CC_REF_PTR_SAFE_RETAIN(_ptr); } 6、//析构函数,对指向动态内存的_ptr进行释放 inline~RefPtr() { CC_REF_PTR_SAFE_RELEASE_NULL(_ptr); } —最后:对自定义的数据类型,如需分配动态内存,令其继承自Ref,使用智能指针RefPtr来管理其内存的释放 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |