CCARRAY FOREACH應用誤區

2021-06-16 21:17:42 字數 1696 閱讀 2820

posted by :

aquaporcus on : 

2013 年 7 月 17 日

0

category:

程式組tags:

cocos2d-x, debug

背景:ccarray是cocos2d-x提供的非常好用乙個容器類,為了方便對遍歷容器裡面的元素,2dx提供了ccarray_foreach這樣的巨集。

問題引入:

現在在做的乙個塔防專案,惡魔打天使,每乙個天使都存放在乙個ccarray物件m_pmonsterarray中。在乙個schedue中判斷,當天使死掉後,就從m_pmonsterarray中刪除。**想當然的寫成如下:

一開是沒仔細注意看,然後看結果好像也是對的。後來為了定位另外乙個問題,加了一些log資訊,才發現這段**隱藏的bug。

問題定位:

為了方便除錯,將所有monster的hp都設定為0,預期只要執行一次上面的**,m_pmonsterarray就應該被清空。但是實際上第一輪沒執行完,就已經報了」std::__non_rtti_object at memory location 0x003ef430″的錯誤,列印出來的log如下:

add monster, uid=78

add monster, uid=79

add monster, uid=80

add monster, uid=81

add monster, uid=82

add monster, uid=83

add monster, uid=84

add monster, uid=85

add monster, uid=86

add monster, uid=87

******************

the 1 times calling update

clear monster, uid=78

clear monster, uid=80

clear monster, uid=82

clear monster, uid=84

clear monster, uid=86

clear monster, uid=87

從log中可以看出,刪除的時候是隔乙個刪乙個,與我們便利array中所有元素的初衷相差甚遠,所以,一定是什麼地方用錯了。

首先仔細看看ccarray_foreach這個巨集,可以在cocoa/ccarray.h中找到它的定義

這裡採用了指標移動的方式來提高效率。看到這個,大概心裡有個數了,因為在array中刪除了乙個元素,如果這個元素後面的所有元素指標都「向前移動一次」,那麼就會導致這種情況。為了確認這個想法,繼續看ccarray的removeobject方法,一路追下去,其最終呼叫了support/data_support/ccarray.cpp中的 ccarrayremoveobjectatindex函式。

確實,在移除需要移除的元素後,其後的所有元素都「向前移動一次」。

因此,在ccarray_foreach中進行removeobject是一種非常不安全的操作,可能導致漏刪,或者導致陣列越界(用ccarray_foreach為下溢,用ccarray_foreach_reverse為上溢)。

解決方案:

我用了乙個比較笨的解決方案,先在ccarray_foreach中將所有需要刪除的元素放在乙個臨時ccaarry物件中,然後再遍歷該臨時ccarray,從m_pmonsterarray中刪除,**如下:

Silverlight Caliburn應用框架2

silverlight caliburn應用框架1 silverlight caliburn應用框架2 silverlight caliburn應用框架3 silverlight caliburn應用框架4 silverlight caliburn應用框架5 silverlight caliburn...

FormsAuthentication應用之登入

配置項描述 name aspxauth loginurl login.aspx defaulturl default.aspx protection all timeout 30 path requiressl false slidingexpiration false cookieless use...

jquery easyui table 典型應用

主要介紹以下幾種功能的典型應用,並列出 提供參考 動態載入資料字段修改樣式,使用styler字段修改文字長度自適應批量的操作 1,動態載入資料 datagrid getdatagrid nowrap false,columns else else if value 警報 else if value ...