關於野指針,我覺得最可怕的情況就是,它在程序大部分時候都不會出錯,當你項目越來越大的時候,可能就會出現各種隨機性詭異錯誤了,而這時你壓根就不會想到是自己很久前的一次疏忽。
我在shero裏用的實體框架是這樣的,邏輯對象爲Entity,視覺對象爲Visual,Visual根據Entity來渲染自己,所以它保存了一個Entity指針m_pEntity。
更新流程是:
Entity->Update();
Visual->Update();
當Entity需要刪除時,將m_canDel置爲true。
所以在EntityManager的更新裏就是這樣:
if (m_canDel) delete pEntity;
但是Viusual怎麼辦呢,Entity沒有保存Visual指針,沒法通知它需要刪除,所以我是這樣更新的:
if(m_pEntity->CanDel()) delete pVisual;
倒黴的是,當m_pEntity爲野指針後,m_pEntity->CanDel()還真爲true。。所以一直沒發覺。
DEBUG就是這樣,源頭找到後就會覺得很簡單,如果就這樣自大的一笑了之,那以後肯定繼續被它虐。所以重要的還是對過程的一些反思:
首先,我這種情況就會產生一些隨機性詭異錯誤,而且源頭是在其他模塊裏,比如這個BUG很早以來就一直存在,而且很早前我也發現過一個由於它導致的堆損壞。當時我查到的源頭是在Audio模塊裏,而且只是某個怪物的音效纔會出錯。所以,我當時的結論是:嗯,這個怪物的音效文件有誤,以後給它換過就沒問題了。
後來,又是CEGUI出錯,而且這次不是提示堆損壞,直接run time error指針錯誤。鬱悶,換回WIN7,運行居然一切正常,懷疑又是哪裏的庫版本不對,想半天沒有結果。
又蛋疼的持續2天調試一些根本沒有問題的模塊。後來,採用註釋法把這些出錯的模塊註釋掉,回到了很久前的一個遊戲結構。再採用極限法,加大產生Entity的速度,然後也是不停刪除他們。 果然,找到了其實是自己很久前的一次野指針疏忽,導致這麼多詭異錯誤。。。
總結幾點:
- VS提供了堆檢查機制,但是它是有限的,比如野指針操作導致內存錯亂這種情況,它很難檢查到。
- XP下運行出現run time error,WIN7下運行正常,這是因爲WIN7的堆管理要先進一些,野指針導致的錯誤要難觸發一些。囧,網上搜了很久,貌似還沒人出現過這種情況。
- SAFE_DELETE能避免一些野指針錯誤,但是不要忘了,指針可能賦值在其他地方,你用SAFE_DELETE把指針置0後,其他地方的指針還是野指針。