一、解决需求

C++标准库的shared_ptr智能指针可以实现对动态内存的管理,避免使用new、delete带来的内存管理问题。但是它线程安全,不够高效,且shared_ptr内部的引用计数不能和cocos的内存管理模型(retain、release)很好的结合。所以有必要实现一个更轻量级的、更契合cocos对象的智能指针。

二、原理

基本原理和shared_ptr一样,是模板。
管理的对象是cocos对象,即Ref的子类对象。
通过实现类的拷贝控制来管理对象的引用计数。

三、支持的操作

初始化操作

  1. // 一个cocos的智能指针,ptr._ptr指向T类型对象,T必须继承自Ref
  2. RefPtr<T> ptr; // ptr._ptr为nullptr
  3. RefPtr<T> ptr = nullptr; // ptr._ptr为nullptr
  4. T* t = new T;
  5. RefPtr<T> ptr1 = t; // ptr1._ptr = t;
  6. // t->retain();
  7. RefPtr<T> ptr2(t); // 同上。
  8. RefPtr<T> ptr3(ptr2); // 拷贝构造,
  9. // ptr3._ptr = ptr2._ptr;
  10. // ptr3._ptr->retain();
  11. //快速生成
  12. RefPtr<T> ptr1 = makeRef(t); //类似make_pair,返回RefPtr<T>类型

赋值操作

  1. T * t = new T;
  2. RefPtr<T> ptr1 = new T;
  3. RefPtr<T> ptr2 = new T;
  4. ptr1 = ptr2; // 拷贝赋值,过程:
  5. // 1、ptr2._ptr->reain();
  6. // 2、ptr1._ptr->release();
  7. // 3、ptr1._ptr = ptr2._ptr;
  8. ptr1 = std::move(ptr2); //移动赋值,过程:
  9. // 1、ptr1._ptr->release();
  10. // 2、ptr1._ptr = ptr2._ptr;
  11. // 3、ptr2._ptr = nullptr;
  12. ptr1 = t; // 拷贝赋值,过程:
  13. // 1、t->retain();
  14. // 2、ptr1._ptr->release();
  15. // 3、ptr1._ptr = t;
  16. ptr1 = nullptr; // ptr1._ptr->release();
  17. // ptr1._ptr = nullptr;
  18. // 注意,ptr1并没有变成nullptr
  19. ptr1.reset(); // 同ptr1 = nullptr
  20. swap(ptr1, ptr2); // 交换对象
  21. // ptr1指向ptr2的对象,不会增加对象的引用计数
  22. ptr1.weakAssign(ptr2); // ptr1._ptr->release();
  23. // ptr1._ptr = ptr2._ptr;

其他操作

  1. // 像操作T一样操作RefPtr
  2. T &t = *ptr1; // 返回对象的引用
  3. ptr1->fuck(); // 等价于t.fuck(),fuck是对象的方法,
  4. T *t = ptr.get(); // 返回对象的指针
  5. // 关系运算,本质上就是对象的关系运算。
  6. ptr1 == ptr2; // 等价于t1 == t2
  7. ptr1 == nullptr; // 等价于t1 == nullptr
  8. ptr1 == t2; // 等价于t1 == t2
  9. ptr1 > ptr2; // 等价于t1 > t2
  10. ptr1 > t2; // 等价于t1 < t2
  11. Vector<T*> v;
  12. v.push_back(ptr1); // 等价于v.push_back(ptr1._ptr)
  13. // 逻辑运算,本质上也是对象的逻辑运算
  14. if( ptr1 ){ // 等价于t1 != nullptr;
  15. }

四、源代码

这里就列出了五个拷贝控制成员,来显示其原理。

  • 拷贝构造
  • 拷贝赋值
  • 移动构造
  • 移动赋值
  • 析构函数 ```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 { //Vector v;

    1. //v.push_back(ptr);,直接插入_ptr而不是智能指针本身。

    return _ptr; } RefPtr & operator = (const RefPtr & other) //拷贝赋值 { if (other._ptr != _ptr) {

    1. CC_REF_PTR_SAFE_RETAIN(other._ptr);
    2. CC_REF_PTR_SAFE_RELEASE(_ptr);
    3. _ptr = other._ptr;

    }

    return *this; }

    RefPtr & operator = (RefPtr && other) //移动赋值 { if (&other != this) {

    1. CC_REF_PTR_SAFE_RELEASE(_ptr);
    2. _ptr = other._ptr;
    3. other._ptr = nullptr;

    }

    return *this; }

    RefPtr & operator = (T * other) //直接赋值T类型对象 { if (other != _ptr) {

    1. CC_REF_PTR_SAFE_RETAIN(other);
    2. CC_REF_PTR_SAFE_RELEASE(_ptr);
    3. _ptr = other;

    }

    return *this; } }

/**

  1. * This function assigns to this RefPtr<T> but does not increase the reference count of the object pointed to.
  2. * Useful for assigning an object created through the 'new' operator to a RefPtr<T>. Basically used in scenarios
  3. * where the RefPtr<T> has the initial ownership of the object.
  4. *
  5. * E.G:
  6. * RefPtr<cocos2d::Image> image;
  7. * image.weakAssign(new cocos2d::Image());
  8. *
  9. * Instead of:
  10. * RefPtr<cocos2d::Image> image;
  11. * image = new cocos2d::Image();
  12. * image->release(); // Required because new'd object already has a reference count of '1'.
  13. */

// 达到类C++的弱引用效果,使用场景如下: // RefPtr image; // image.weakAssign(new cocos2d::Image()); // 代替以下场景: // RefPtr image; // image = new cocos2d::Image(); // image->release(); // 但这并不是真正意义上的弱引用,只是在传递的时候弱引用(没有增加引用计数) // 但是本身还是一个RefPtr强引用,依然可以改变对象的引用计数 void weakAssign(const RefPtr & other) { CC_REF_PTR_SAFE_RELEASE(_ptr); _ptr = other._ptr; }

  1. <a name="uyPcw"></a>
  2. # 五、缺陷
  3. cocos模仿了shared_ptr,却没有模仿weak_ptr,没有真正的弱引用。
  4. ```cpp
  5. T * t = new T;
  6. RefPtr<T> ptr;
  7. RefPtr<T> ptr1(t);
  8. RefPtr<T> ptr2;
  9. ptr.weakAssign(t);
  10. ptr.release(); // ptr虽然是弱引用t,但ptr却可以改变t的引用计数,这他娘的还是弱引用?
  11. // C++的weak_ptr只能弱引用shared_ptr,
  12. // 访问对象只能通过lock获得shared_ptr进行操作。