标签:接收 .cpp 解释 pop imm sof 代码 3.2 版本号
比較著名的使用引用计数的有COM和Objective-C,在COM的IUnknow接口中定义了三个函数:QueryInterface。AddRef和Release,它们分别用于获取接口对象、给接口对象添加计数,给接口对象降低计数,当内部计数变为0时,自己主动销毁接口对象。
在Objective-C中,则定义了retain,release和autorelease函数,分别用于添加计数、降低计数以及将一个对象交给自己主动释放池对象AutoreleasePool进行管理,由AutoreleasePool对象负责调用release函数。
【Ref类的实现】
因为Cocos2d-x是在Cocos2d-iPhone的基础上发展而来,所以沿用了非常多Objective-C的思想。Ref类的实现就是如此。
Ref类实现了引用计数的功能,它是引擎代码中绝大多数其它类的父类,定义在CCRef.h中。实如今CCRef.cpp中。事实上在CCRef.h文件里不止定义了Ref类。还定义了Clonable类、一系列的宏定义和类型定义。只是我们暂且将精力放在Ref类的解读上。Ref类使用私有成员变量_referenceCount保存计数值。并通过retain,release和autorelease函数实现增减计数值。
class CC_DLL Ref { public: /** * Retains the ownership. * * This increases the Ref‘s reference count. * * @see release, autorelease * @js NA */ void retain(); /** * Releases the ownership immediately. * * This decrements the Ref‘s reference count. * * If the reference count reaches 0 after the descrement, this Ref is * destructed. * * @see retain, autorelease * @js NA */ void release(); /** * Releases the ownership sometime soon automatically. * * This descrements the Ref‘s reference count at the end of current * autorelease pool block. * * If the reference count reaches 0 after the descrement, this Ref is * destructed. * * @returns The Ref itself. * * @see AutoreleasePool, retain, release * @js NA * @lua NA */ Ref* autorelease(); /** * Returns the Ref‘s current reference count. * * @returns The Ref‘s reference count. * @js NA */ unsigned int getReferenceCount() const; protected: /** * Constructor * * The Ref‘s reference count is 1 after construction. * @js NA */ Ref(); public: /** * @js NA * @lua NA */ virtual ~Ref(); protected: /// count of references unsigned int _referenceCount; friend class AutoreleasePool; };Ref将构造函数声明为保护类型,防止直接生成Ref对象。在构造函数的成员初始化列表中将引用计数值_referenceCount初始化为1。retain函数将_referenceCount加1,release函数则减1。autorelease函数则将对象托管给AutoreleasePool对象进行管理,详细实现代码例如以下:
NS_CC_BEGIN Ref::Ref() : _referenceCount(1) // when the Ref is created, the reference count of it is 1 { } Ref::~Ref() { } void Ref::retain() { CCASSERT(_referenceCount > 0, "reference count should greater than 0"); ++_referenceCount; } void Ref::release() { CCASSERT(_referenceCount > 0, "reference count should greater than 0"); --_referenceCount; if (_referenceCount == 0) { delete this; } } Ref* Ref::autorelease() { PoolManager::getInstance()->getCurrentPool()->addObject(this); return this; } unsigned int Ref::getReferenceCount() const { return _referenceCount; } NS_CC_END【Clonable类的定义】
/** Interface that defines how to clone an Ref */ class CC_DLL Clonable { public: /** returns a copy of the Ref */ virtual Clonable* clone() const = 0; /** * @js NA * @lua NA */ virtual ~Clonable() {}; /** returns a copy of the Ref. * @deprecated Use clone() instead */ CC_DEPRECATED_ATTRIBUTE Ref* copy() const { // use "clone" instead CC_ASSERT(false); return nullptr; } };【回调函数的定义】
typedef void (Ref::*SEL_CallFunc)(); typedef void (Ref::*SEL_CallFuncN)(Node*); typedef void (Ref::*SEL_CallFuncND)(Node*, void*); typedef void (Ref::*SEL_CallFuncO)(Ref*); typedef void (Ref::*SEL_MenuHandler)(Ref*); typedef void (Ref::*SEL_SCHEDULE)(float); #define callfunc_selector(_SELECTOR) static_cast<cocos2d::SEL_CallFunc>(&_SELECTOR) #define callfuncN_selector(_SELECTOR) static_cast<cocos2d::SEL_CallFuncN>(&_SELECTOR) #define callfuncND_selector(_SELECTOR) static_cast<cocos2d::SEL_CallFuncND>(&_SELECTOR) #define callfuncO_selector(_SELECTOR) static_cast<cocos2d::SEL_CallFuncO>(&_SELECTOR) #define menu_selector(_SELECTOR) static_cast<cocos2d::SEL_MenuHandler>(&_SELECTOR) #define schedule_selector(_SELECTOR) static_cast<cocos2d::SEL_SCHEDULE>(&_SELECTOR)上面回调函数的定义分为两步:类型定义和宏定义。我们以SEL_CallFuncO为例进行说明,首先通过typedef类型定义了一个成员函数指针SEL_CallFuncO。SEL_CallFuncO是Ref类的成员,同一时候接收Ref类型的指针形參:
【内存泄漏的检測】
在上面解说Ref实现过程中,我们有益忽略了一些次要的代码,当中就包含内存泄漏检測。这部分代码是以宏:
#define CC_USE_MEM_LEAK_DETECTION 0
作为开关的。
内存泄漏检測代码主要包含Ref类静态成员函数:
class CC_DLL Ref { // Memory leak diagnostic data (only included when CC_USE_MEM_LEAK_DETECTION is defined and its value isn‘t zero) #if CC_USE_MEM_LEAK_DETECTION public: static void printLeaks(); #endif };
定义在CCRef.cpp文件内的静态函数(静态函数与普通函数不同之处在于。它仅仅在声明它的文件里可见,其它文件不可见。同一时候,其它文件里能够定义同样名字的函数,不会发生冲突)
#if CC_USE_MEM_LEAK_DETECTION static void trackRef(Ref* ref); static void untrackRef(Ref* ref); #endiftrackRef函数在Ref类对象创建的时候调用,untrackRef在Ref类对象销毁的时候调用。Ref对象实例保存在静态链表__refAllocationList中,实现代码例如以下所看到的:
#if CC_USE_MEM_LEAK_DETECTION static std::list<Ref*> __refAllocationList; void Ref::printLeaks() { // Dump Ref object memory leaks if (__refAllocationList.empty()) { log("[memory] All Ref objects successfully cleaned up (no leaks detected).\n"); } else { log("[memory] WARNING: %d Ref objects still active in memory.\n", (int)__refAllocationList.size()); for (const auto& ref : __refAllocationList) { CC_ASSERT(ref); const char* type = typeid(*ref).name(); log("[memory] LEAK: Ref object ‘%s‘ still active with reference count %d.\n", (type ? type : ""), ref->getReferenceCount()); } } } static void trackRef(Ref* ref) { CCASSERT(ref, "Invalid parameter, ref should not be null!"); // Create memory allocation record. __refAllocationList.push_back(ref); } static void untrackRef(Ref* ref) { auto iter = std::find(__refAllocationList.begin(), __refAllocationList.end(), ref); if (iter == __refAllocationList.end()) { log("[memory] CORRUPTION: Attempting to free (%s) with invalid ref tracking record.\n", typeid(*ref).name()); return; } __refAllocationList.erase(iter); } #endif // #if CC_USE_MEM_LEAK_DETECTION
[当我在研究Cocos-2dx的源代码时,我在想什么]-Ref类,一切的起源
标签:接收 .cpp 解释 pop imm sof 代码 3.2 版本号
原文地址:http://www.cnblogs.com/claireyuancy/p/6959208.html