一、解决需求
C++标准库的shared_ptr智能指针可以实现对动态内存的管理,避免使用new、delete带来的内存管理问题。但是它线程安全,不够高效,且shared_ptr内部的引用计数不能和cocos的内存管理模型(retain、release)很好的结合。所以有必要实现一个更轻量级的、更契合cocos对象的智能指针。
二、原理
基本原理和shared_ptr一样,是模板。
管理的对象是cocos对象,即Ref的子类对象。
通过实现类的拷贝控制来管理对象的引用计数。
三、支持的操作
初始化操作
// 一个cocos的智能指针,ptr._ptr指向T类型对象,T必须继承自Ref
RefPtr<T> ptr; // ptr._ptr为nullptr
RefPtr<T> ptr = nullptr; // ptr._ptr为nullptr
T* 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并没有变成nullptr
ptr1.reset(); // 同ptr1 = nullptr
swap(ptr1, ptr2); // 交换对象
// ptr1指向ptr2的对象,不会增加对象的引用计数
ptr1.weakAssign(ptr2); // ptr1._ptr->release();
// ptr1._ptr = ptr2._ptr;
其他操作
// 像操作T一样操作RefPtr
T &t = *ptr1; // 返回对象的引用
ptr1->fuck(); // 等价于t.fuck(),fuck是对象的方法,
T *t = ptr.get(); // 返回对象的指针
// 关系运算,本质上就是对象的关系运算。
ptr1 == ptr2; // 等价于t1 == t2
ptr1 == nullptr; // 等价于t1 == nullptr
ptr1 == t2; // 等价于t1 == t2
ptr1 > ptr2; // 等价于t1 > t2
ptr1 > t2; // 等价于t1 < t2
Vector<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,没有真正的弱引用。
```cpp
T * 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进行操作。