zoukankan      html  css  js  c++  java
  • Cocos2d-x 3.2 智能指针

    Cocos2d-x 3.2:智能指针

    本文转载自深入理解Cocos2d-x 3.x:内置数据结构(1)智能指针

    智能指针在 C++ 11 的标准中已经存在了,分别是unique_ptr,shared_ptr,weak_ptr,其中最常用的应该是share_ptr,它采用引用计数的方 式管理内存,当引用计数为0的时候,自动释放内存,但是由于shared_ptr考虑到了线程安全,所以会存在有较大的性能损失。所以在实时游戏开发中, 往往不会用到shared_ptr。

    在Cocos2d-x 3.2以及更高的版本中,Cocos2d-x提供了自己的智能指针方案——RefPtr,这套方案实际上也是模仿C++11中的shared_ptr机制 实现的,他结合了Cocos2d-x自身的引用计数来管理内存,当然为了性能,他牺牲了线程安全(Cocos2d-x的引用计数不支持线程安全)。

    下面看看Cocos2d-x中智能指针的源码,首先是构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    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宏了,它是智能指针专用的宏,在外部是引用不到的。实现如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #define CC_REF_PTR_SAFE_RETAIN(ptr)  
          
        do  
        {  
            if (ptr)  
            {  
                const_cast<Ref*>(static_cast<const Ref*>(ptr))->retain();  
            }  
          
        }   while (0);

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //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);

    接下来看看析构函数

    1
    2
    3
    4
    inline ~RefPtr()  
    {  
        CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);  
    }

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #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并且置空。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    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;  
    }

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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,它对保持对一个指针的弱引用,实现如下:

    1
    2
    3
    4
    5
    inline void weakAssign(const RefPtr<T> & other)  
    {  
        CC_REF_PTR_SAFE_RELEASE(_ptr);  
        _ptr = other._ptr;  
    }

    相对于其他的复制函数,他少了retain操作,说明它并不保持对other的强引用,但是析构的时候我们发现,依旧会release一次,那么这个函数会有什么奇妙的作用呢。看下面的函数片段

    1
    2
    3
    4
    5
    6
    7
    8
    void a()  
    {  
        RefPtr<Texture2D> l;  
        l.weakAssign(new Texture2D);  
        // -- doSomething  
       
        return;  
    }

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

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

    但是这一种方法的释放时机是在一帧的结束,而智能指针的释放时机是函数的结束,所以相较于下一种方法,智能指针会效率更高。

  • 相关阅读:
    用Eclipse+MyEclipse开发struts的一个经典的实例(转)
    TOMCAT配置虚拟目录
    翻动100万级的数据(自定义的MSSQL分页查询过程)
    MyEclipse Hibernate 快速入门中文版
    微软提供的数据访问组件SqlHelper
    Java内存管理(一、内存分配)
    使用commonlogging与log4j打印日志,发现版本冲突
    Java内存管理(二、Java垃圾回收)
    初探java内存机制_堆和栈
    关于单CPU,多CPU上的原子操作
  • 原文地址:https://www.cnblogs.com/dudu580231/p/4560038.html
Copyright © 2011-2022 走看看