zoukankan      html  css  js  c++  java
  • cocos2d智能指针 转自:http://blog.csdn.net/nxshow/article/details/44699409

    智能指针在C++11的标准中已经存在了,

    分别是unique_ptr,shared_ptr,weak_ptr,

    其中最常用的应该是share_ptr,

    它采用引用计数的方式管理内存,

    当引用计数为0的时候,

    自动释放内存,

    但是由于shared_ptr考虑到了线程安全,

    所以会存在有较大的性能损失。

    所以在实时游戏开发中,

    往往不会用到shared_ptr。

    在cocos2d-x3.2以及更高的版本中,

    cocos2d-x提供了自己的智能指针方案——RefPtr,

    这套方案实际上也是模仿C++11中的shared_ptr机制实现的,

    他结合了Cocos2d-x自身的引用计数来管理内存,

    当然为了性能,

    他牺牲了线程安全(cocos2d-x的引用计数不支持线程安全)。

    下面看看cocos2d-x中智能指针的源码,

    首先是构造函数

    inline RefPtr()
    :
    _ptr(nullptr)
    {

    }

    inline RefPtr(RefPtr<T> && other)
    {
    _ptr = other._ptr;
    other._ptr = nullptr;
    }

    inline RefPtr(T * ptr)
    :
    _ptr(const_cast<typename std::remove_const<T>::type*>(ptr)) // Const cast allows RefPtr<T> to reference objects marked const too.
    {
    CC_REF_PTR_SAFE_RETAIN(_ptr);
    }


    inline RefPtr(std::nullptr_t ptr)
    :
    _ptr(nullptr)
    {

    }

    inline RefPtr(const RefPtr<T> & other)
    :
    _ptr(other._ptr)
    {
    CC_REF_PTR_SAFE_RETAIN(_ptr);
    }

    RefPtr提供了多个构造函数,

    可以用默认构造函数声明一个空智能指针,

    用别的指针来声明一个智能指针,

    也提供了移动构造函数将内存偷过来,

    复制构造函数保持内存的强引用。

    构造函数最为重要的莫过于CC_REF_PTR_SAFE_RETAIN宏了,

    它是智能指针专用的宏,

    在外部是引用不到的。

    实现如下

    #define CC_REF_PTR_SAFE_RETAIN(ptr)

    do
    {
    if (ptr)
    {
    const_cast<Ref*>(static_cast<const Ref*>(ptr))->retain();
    }

    } while (0);

    核心就是retain,保持一个强引用。

    下面是声明智能指针的用法

    //inline RefPtr()
    RefPtr<int> a;
    //inline RefPtr(T * ptr)
    RefPtr<int> b(new int);
    //inline RefPtr(const RefPtr<T> & other)
    RefPtr<int>c(b);
    //inline RefPtr(RefPtr<T> && other)
    RefPtr<int>d(std::move(b));
    //inline RefPtr(std::nullptr_t ptr)
    RefPtr<int>d(nullptr);

    接下来看看析构函数

    inline ~RefPtr()
    {
    CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
    }

    析构函数就简单多了,只有一个,具体还是要到宏里面。

    #define CC_REF_PTR_SAFE_RELEASE_NULL(ptr)

    do
    {
    if (ptr)
    {
    const_cast<Ref*>(static_cast<const Ref*>(ptr))->release();
    ptr = nullptr;
    }

    } while (0);

    实际上就是对其release并且置空。

    另外,也提供了移动赋值函数以及赋值函数

    inline RefPtr<T> & operator = (RefPtr<T> && other)
    {
    if (&other != this)
    {
    CC_REF_PTR_SAFE_RELEASE(_ptr);
    _ptr = other._ptr;
    other._ptr = nullptr;
    }

    return *this;
    }

    inline RefPtr<T> & operator = (T * other)
    {
    if (other != _ptr)
    {
    CC_REF_PTR_SAFE_RETAIN(other);
    CC_REF_PTR_SAFE_RELEASE(_ptr);
    _ptr = const_cast<typename std::remove_const<T>::type*>(other); // Const cast allows RefPtr<T> to reference objects marked const too.
    }

    return *this;
    }

    inline RefPtr<T> & operator = (std::nullptr_t other)
    {
    CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
    return *this;
    }

    第一个是移动赋值函数,第二个是赋值函数,第三个是置空专门用于下列场景

    RefPtr<int> b(new int);
    b = nullptr;

    RefPtr还重载了指针操作符 *和-> 方便直接调用内部指针,所以其使用方法与普通指针一样。也提供了get方法获取到指针

    inline operator T * () const { return reinterpret_cast<T*>(_ptr); }

    inline T & operator * () const
    {
    CCASSERT(_ptr, "Attempt to dereference a null pointer!");
    return reinterpret_cast<T&>(*_ptr);
    }

    inline T * operator->() const
    {
    CCASSERT(_ptr, "Attempt to dereference a null pointer!");
    return reinterpret_cast<T*>(_ptr);
    }

    inline T * get() const { return reinterpret_cast<T*>(_ptr); }

    还重载了一系列的操作符,这里就不做分析了,最后还有一个比较关键的函数,weakAssign,它对保持对一个指针的弱引用,实现如下:

    inline void weakAssign(const RefPtr<T> & other)
    {
    CC_REF_PTR_SAFE_RELEASE(_ptr);
    _ptr = other._ptr;
    }

    相对于其他的复制函数,他少了retain操作,

    说明它并不保持对other的强引用,

    但是析构的时候我们发现,

    依旧会release一次,那么这个函数会有什么奇妙的作用呢。

    看下面的函数片段

    void a()
    {
    RefPtr<Texture2D> l;
    l.weakAssign(new Texture2D);
    // -- doSomething

    return;
    }

    函数中并没有delete,但是依旧不会造成内存泄露,当然,还有一种方法也不会造成内存泄露,也就是

    auto aa = new Texture2D;
    aa->autorelease();

    但是这一种方法的释放时机是在一帧的结束,

    而智能指针的释放时机是函数的结束,

    所以相较于下一种方法,智能指针会效率更高

  • 相关阅读:
    lombok的介绍及使用
    java后端导入excel将数据写入数据库
    java后端导出excel表格
    eclipse maven打war包
    java后端树形菜单使用递归方法
    mybatis一对多查询
    @transactional作用和事务
    zookeeper安装
    Solr单机版安装
    jstat 简介(2)
  • 原文地址:https://www.cnblogs.com/hackerl/p/4795808.html
Copyright © 2011-2022 走看看