【深入了解cocos2d-x 3.x】内置数据结构2——Map

其实最没意思的数据结构就是Map和Vector这两个了,完完全全就是std::map和std::vector上面再加了一层引用计数。当然,这也有好处,就是支持std算法以及支持cocos2d-x的内存管理机制。

看源码可以知道(下均只对Map进行分析,Vector同理)

template <class K,class V>
class Map
{
public:
    // ------------------------------------------
    // Iterators
    // ------------------------------------------
#if USE_STD_UNORDERED_MAP
    typedef std::unordered_map<K,V> RefMap;
#else
    typedef std::map<K,V> RefMap;
#endif
protected:
  RefMap _data;
};

内部的数据结构就是一个std::unordered_map,但是cocos2d-x对其做了一个限制,V必须是由Ref派生出来的数据类型,这样才能支持内存管理机制,下面是构造函数(有多个构造函数,只列举了一个)
    /** Default constructor */
    Map<K,V>()
    : _data()
    {
        static_assert(std::is_convertible<V,Ref*>::value,"Invalid Type for cocos2d::Map<K,V>!");
        CCLOGINFO("In the default constructor of Map!");
    }

static_assert是表示在编译时检查,std::is_convertible是检测V与Ref*是否是继承关系,如果是,value为true,检测通过。如果不是,会在编译期就告诉我们,这个地方编译不过。

接下来就是插入函数

    /** @brief Inserts new elements in the map.
     *  @note If the container has already contained the key,this function will erase the old pair(key,object)  and insert the new pair.
     *  @param key The key to be inserted.
     *  @param object The object to be inserted.
     */
    void insert(const K& key,V object)
    {
        CCASSERT(object != nullptr,"Object is nullptr!");
        erase(key);
        _data.insert(std::make_pair(key,object));
        object->retain();
    }

值得注意的是,这里先有一个删除操作,再进行插入,这样为了保证所有的key都是唯一值,但是这样会多造成一次遍历,因为unordered_map的插入是无序的,所以unordered_map的insert操作的复杂度是O(1),但是erase的删除必须要find key,所以会有O(N)的复杂度,所以效率会比直接使用unordered_map低。

然后是retain,保持对V类型的object的强引用

接下来是删除函数

    /** @brief Removes an element with an iterator from the Map<K,V> container.
     *  @param k Key of the element to be erased.
     *         Member type 'K' is the type of the keys for the elements in the container,*         defined in Map<K,V> as an alias of its first template parameter (Key).
     */
    size_t erase(const K& k)
    {
        auto iter = _data.find(k);
        if (iter != _data.end())
        {
            iter->second->release();
            _data.erase(iter);
            return 1;
        }
        
        return 0;
    }
首先find到K,然后先执行release,再删除,返回1表示删除成功,0表示删除失败。

还有一些有意思的函数,如下这个

    V getRandomObject() const
    {
        if (!_data.empty())
        {
            ssize_t randIdx = rand() % _data.size();
            const_iterator randIter = _data.begin();
            std::advance(randIter,randIdx);
            return randIter->second;
        }
        return nullptr;
    }
函数的作用是返回一个随机对象,首先判断非空,然后获取一个(0-data.size)的随机数,使用std::advance给begin增加一个随机数的长度,返回这个长度的迭代器。

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...