一、解决需求
C++标准库的shared_ptr智能指针可以实现对动态内存的管理,避免使用new、delete带来的内存管理问题。但是它线程安全,不够高效,且shared_ptr内部的引用计数不能和cocos的内存管理模型(retain、release)很好的结合。所以有必要实现一个更轻量级的、更契合cocos对象的智能指针。
二、原理
基本原理和shared_ptr一样,是模板。
管理的对象是cocos对象,即Ref的子类对象。
通过实现类的拷贝控制来管理对象的引用计数。
三、支持的操作
初始化操作
// 一个cocos的智能指针,ptr._ptr指向T类型对象,T必须继承自RefRefPtr<T> ptr; // ptr._ptr为nullptrRefPtr<T> ptr = nullptr; // ptr._ptr为nullptrT* t = new T;RefPtr<T> ptr1 = t; // ptr1._ptr = t;// t->retain();RefPtr<T> ptr2(t); // 同上。RefPtr<T> ptr3(ptr2); // 拷贝构造,// ptr3._ptr = ptr2._ptr;// ptr3._ptr->retain();//快速生成RefPtr<T> ptr1 = makeRef(t); //类似make_pair,返回RefPtr<T>类型
赋值操作
T * t = new T;RefPtr<T> ptr1 = new T;RefPtr<T> ptr2 = new T;ptr1 = ptr2; // 拷贝赋值,过程:// 1、ptr2._ptr->reain();// 2、ptr1._ptr->release();// 3、ptr1._ptr = ptr2._ptr;ptr1 = std::move(ptr2); //移动赋值,过程:// 1、ptr1._ptr->release();// 2、ptr1._ptr = ptr2._ptr;// 3、ptr2._ptr = nullptr;ptr1 = t; // 拷贝赋值,过程:// 1、t->retain();// 2、ptr1._ptr->release();// 3、ptr1._ptr = t;ptr1 = nullptr; // ptr1._ptr->release();// ptr1._ptr = nullptr;// 注意,ptr1并没有变成nullptrptr1.reset(); // 同ptr1 = nullptrswap(ptr1, ptr2); // 交换对象// ptr1指向ptr2的对象,不会增加对象的引用计数ptr1.weakAssign(ptr2); // ptr1._ptr->release();// ptr1._ptr = ptr2._ptr;
其他操作
// 像操作T一样操作RefPtrT &t = *ptr1; // 返回对象的引用ptr1->fuck(); // 等价于t.fuck(),fuck是对象的方法,T *t = ptr.get(); // 返回对象的指针// 关系运算,本质上就是对象的关系运算。ptr1 == ptr2; // 等价于t1 == t2ptr1 == nullptr; // 等价于t1 == nullptrptr1 == t2; // 等价于t1 == t2ptr1 > ptr2; // 等价于t1 > t2ptr1 > t2; // 等价于t1 < t2Vector<T*> v;v.push_back(ptr1); // 等价于v.push_back(ptr1._ptr)// 逻辑运算,本质上也是对象的逻辑运算if( ptr1 ){ // 等价于t1 != nullptr;}
四、源代码
这里就列出了五个拷贝控制成员,来显示其原理。
- 拷贝构造
- 拷贝赋值
- 移动构造
- 移动赋值
析构函数 ```cpp template
class RefPtr { public: RefPtr() //默认构造 : _ptr(nullptr){ } RefPtr(const RefPtr
& other) //拷贝构造函数 : _ptr(other._ptr) { CC_REF_PTR_SAFE_RETAIN(_ptr); }
RefPtr(RefPtr&& other) //移动构造函数, { _ptr = other._ptr; other._ptr = nullptr; } RefPtr(T ptr) //转换构造,RefPtr ptr = new T; : _ptr(ptr) { CC_REF_PTR_SAFE_RETAIN(_ptr); } ~RefPtr() //析构 { CC_REF_PTR_SAFE_RELEASE_NULL(_ptr); } operator T () const { //Vectorv; //v.push_back(ptr);,直接插入_ptr而不是智能指针本身。
return _ptr; } RefPtr
& operator = (const RefPtr & other) //拷贝赋值 { if (other._ptr != _ptr) { CC_REF_PTR_SAFE_RETAIN(other._ptr);CC_REF_PTR_SAFE_RELEASE(_ptr);_ptr = other._ptr;
}
return *this; }
RefPtr
& operator = (RefPtr && other) //移动赋值 { if (&other != this) { CC_REF_PTR_SAFE_RELEASE(_ptr);_ptr = other._ptr;other._ptr = nullptr;
}
return *this; }
RefPtr
& operator = (T * other) //直接赋值T类型对象 { if (other != _ptr) { CC_REF_PTR_SAFE_RETAIN(other);CC_REF_PTR_SAFE_RELEASE(_ptr);_ptr = other;
}
return *this; } }
/**
* This function assigns to this RefPtr<T> but does not increase the reference count of the object pointed to.* Useful for assigning an object created through the 'new' operator to a RefPtr<T>. Basically used in scenarios* where the RefPtr<T> has the initial ownership of the object.** E.G:* RefPtr<cocos2d::Image> image;* image.weakAssign(new cocos2d::Image());** Instead of:* RefPtr<cocos2d::Image> image;* image = new cocos2d::Image();* image->release(); // Required because new'd object already has a reference count of '1'.*/
// 达到类C++的弱引用效果,使用场景如下:
// RefPtr
<a name="uyPcw"></a># 五、缺陷cocos模仿了shared_ptr,却没有模仿weak_ptr,没有真正的弱引用。```cppT * t = new T;RefPtr<T> ptr;RefPtr<T> ptr1(t);RefPtr<T> ptr2;ptr.weakAssign(t);ptr.release(); // ptr虽然是弱引用t,但ptr却可以改变t的引用计数,这他娘的还是弱引用?// C++的weak_ptr只能弱引用shared_ptr,// 访问对象只能通过lock获得shared_ptr进行操作。
