天天看點

轉 Cocos2d-x3.0模版容器詳解之一:cocos2d::Vector<T>

1.概述

版本:v3.0 beta

語言:c++

<a href="http://www.cocoachina.com/bbs/#">?</a>

1

<code>template</code>         <code>&lt;</code>         <code>class</code>         <code>t&gt;</code>         <code>class</code>         <code>cc_dll vector;</code>

cocos2d::vector&lt;t&gt; 是一個封裝了動态大小的數組的順序型容器。

我們很細緻地設計了 cocos2d::vector&lt;t&gt; 容器作為 cocos2d::ccarray 的替代品,是以請使用 cocos2d::vector&lt;t&gt; 代替 cocos2d::ccarray。

cocos2d::vector&lt;t&gt; 常用操作的複雜度(效率)如下:

随機通路 - 常量 0(1)

在末尾插入或者移除元素 - 分攤常量 0(1)

插入或移除元素 - cocos2d::vector&lt;t&gt; 長度線性相關 o(n)

2.模版參數

t - 元素類型.

3.記憶體管理

cocos2d::vector&lt;t&gt; 類包含了唯一一個資料成員:

<code>std::vector&lt;t&gt; _data;</code>

_data 的記憶體管理是由編譯器自動處理的。如果你在棧上聲明了一個 cocos2d::vector&lt;t&gt; 對象,那就不需要關心記憶體釋放問題。

如果你調用了 new 操作符來配置設定一塊 cocos2d::vector&lt;t&gt; 的動态記憶體,那就需要在使用完後調用 delete 操作符來釋放記憶體。這同樣适用于 new[] 和 delete[]。

注意:在新 c++ 中,它傾向于本地存儲對象而不是堆存儲對象。是以,請不要調用 new 操作符來配置設定 cocos2d::vector&lt;t&gt; 的堆對象,而是使用棧對象來代替它。

如果你有足夠的理由在堆上動态配置設定 cocos2d::vector&lt;t&gt; 的話,請使用智能指針替換原始指針,比如 shared_ptr,unique_ptr。

警告: cocos2d::vector&lt;t&gt; 不是 cocos2d::object 的子類,是以不再像其他的 cocos2d 類一樣使用 retain/release 和記憶體計數管理。換句話說,你不能對 cocos2d::vector&lt;t&gt; 本身調用 retain,release等等操作。

4.基本用法

我們用一個統一的接口外加 cocos2d-x 的記憶體管理規則來封裝了 std::vector&lt;t&gt; 基本上所有常用的操作。

是以 pushback() 方法現在将會 retain 該函參的所有權,popback() 方法将會 release 容器最後一個元素的所有權。

當你使用這些操作時,你應該加倍注意底層的記憶體管理,這東西對于許多的 cocos2d-x 開發新手是常見陷阱。

警告:cocos2d::vector&lt;t&gt; 沒有重載 operator[],是以你不能使用像 vec 這樣的操作來試圖從 cocos2d::vector&lt;t&gt; 擷取元素。

cocos2d::vector&lt;t&gt; 容器提供了許多不同種類的疊代器。我們受益于 c++ 标準庫的标準基礎設施;例如,大量專用的标準通用算法和 for_each 循環。

除了 std::vector&lt;t&gt; 容器操作,我們還添加了很多标準算法到 cocos2d::vector&lt;t&gt;,比如 std::find,std::reverse 和 std::swap,這樣簡化了很多有用的、常用的操作。

更多 api 的使用,請參考引擎源碼和 cocos2d-x 3.0 beta 已實作的測試例。

這裡提供一個簡單的示例:

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

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

<code>//使用預設大小建立一個 vector&lt;sprite*&gt;,然後往其中加入一個精靈</code>

<code>auto</code>         <code>sp0 = sprite::create();</code>

<code>sp0-&gt;settag(0);</code>

<code>//這裡我們 demo 使用了 shared_ptr,在你的代碼中,請使用棧對象替代 </code>

<code>std::shared_ptr&lt;vector&lt;sprite*&gt;&gt;  vec0 = std::make_shared&lt;vector&lt;sprite*&gt;&gt;();  </code>         <code>//default constructor</code>

<code>vec0-&gt;pushback(sp0);</code>

<code> </code> 

<code>//使用capacity為5來建立一個 vector&lt;object*&gt;,然後往其中加入一個精靈</code>

<code>auto</code>         <code>sp1 = sprite::create();</code>

<code>sp1-&gt;settag(1);</code>

<code>//用一個容量初始化一個 vector</code>

<code>vector&lt;sprite*&gt;  vec1(5);</code>

<code>//在一個确定的位置插入一個确定的對象</code>

<code>vec1.insert(0, sp1);</code>

<code>//我們也可以加入一整個 vector</code>

<code>vec1.pushback(*vec0);</code>

<code>for</code>         <code>(</code>         <code>auto</code>         <code>sp : vec1)</code>

<code>{</code>

<code>    </code>        <code>log</code>         <code>(</code>         <code>"sprite tag = %d"</code>         <code>, sp-&gt;gettag());</code>

<code>}</code>

<code>vector&lt;sprite*&gt; vec2(*vec0);</code>

<code>if</code>         <code>(vec0-&gt;equals(vec2)) { </code>        <code>//如果兩個 vector 相同的話傳回真</code>

<code>    </code>        <code>log</code>         <code>(</code>         <code>"pvec0 is equal to pvec2"</code>         <code>);</code>

<code>if</code>         <code>(!vec1.empty()) {  </code>         <code>//判斷 vector 是否為空</code>

<code>    </code>        <code>//擷取 vector 的 capacity 和 size,要注意的是 capacity 并不一定等于 size</code>

<code>    </code>        <code>if</code>         <code>(vec1.capacity() == vec1.size()) {</code>

<code>        </code>        <code>log</code>         <code>(</code>         <code>"pvec1-&gt;capacity()==pvec1-&gt;size()"</code>         <code>);</code>

<code>    </code>        <code>}</code>         <code>else</code>         <code>{</code>

<code>        </code>        <code>vec1.shrinktofit();   </code>        <code>//收縮 vector 以便記憶體對應上元素的數量</code>

<code>        </code>        <code>log</code>         <code>(</code>         <code>"pvec1-&gt;capacity()==%zd; pvec1-&gt;size()==%zd"</code>        <code>,vec1.capacity(),vec1.size());</code>

<code>    </code>        <code>}</code>

<code>    </code>        <code>//pvec1-&gt;swap(0, 1);  //通過索引交換 vector 中的兩個元素</code>

<code>    </code>        <code>vec1.swap(vec1.front(), vec1.back());  </code>         <code>//通過值交換 vector 中的兩個元素 </code>

<code>        </code>        <code>if</code>         <code>(vec2.contains(sp0)) {  </code>         <code>//傳回一個布爾值,用于訓示該對象是否存在于 vector 中</code>

<code>        </code>        <code>log</code>         <code>(</code>         <code>"the index of sp0 in pvec2 is %zd"</code>         <code>,vec2.getindex(sp0));</code>

<code>    </code>        <code>//從 vector 中移除元素</code>

<code>    </code>        <code>vec1.erase(vec1.find(sp0));</code>

<code>    </code>        <code>//pvec1-&gt;erase(1);</code>

<code>    </code>        <code>//pvec1-&gt;eraseobject(sp0,true);</code>

<code>    </code>        <code>//pvec1-&gt;popback();</code>

<code>    </code>        <code>vec1.clear(); </code>        <code>//移除所有元素</code>

<code>    </code>        <code>log</code>         <code>(</code>         <code>"the size of pvec1 is %zd"</code>         <code>,vec1.size());</code>

輸出:

<code>cocos2d: sprite tag = 1</code>

<code>cocos2d: sprite tag = 0</code>

<code>cocos2d: pvec0 is equal to pvec2</code>

<code>cocos2d: pvec1-&gt;capacity()==2; pvec1-&gt;size()==2</code>

<code>cocos2d: the index of sp0 in pvec2 is 0</code>

<code>cocos2d: the size of pvec1 is 0</code>

5.最佳實踐

偏向于使用基于棧建構的 cocos2d::vector&lt;t&gt; 而不使用基于堆建構的 cocos2d::vector&lt;t&gt;。

當将 cocos2d::vector&lt;t&gt; 作為參數進行傳遞的時候,将它聲明為一個常引用,如 const cocos2d::vector&lt;t&gt;&amp;。

當從一個函數中傳回一個 cocos2d::vector&lt;t&gt; 時,簡單地傳回值對象。編譯器将使用移動語義優化這種情況。

不要試圖在 cocos2d::vector&lt;t&gt; 中儲存除 cocos2d::object 子類對象指針以外的其他任意資料類型對象。

繼續閱讀