當使用到 new這個關鍵字時,在C++則必須一定要做Delete的動作(Release),防止產生Memory leak。
Naked Pointer:當使用 naked Pointer,開發時必須記住物件A所控制、產生的指標當物件A被刪除時裡面的指標要做釋放。
EX:在一個關卡,假設有一個EnemyManager控制所有的Enemy物件,當玩家過關要前往下一關,則EnemyManager必需要被釋放(因為玩家過關後這關卡就不需要有敵人),
如果EnemyManager有宣告並使用到Naked Pointer,開發者在釋放EnemyManager時必須要先做naked Pointer的釋放最後才能釋放EnemyManager,
(在EnemyManager有使用到new的關鍵字的指標都必須要先執行Delete的動作),對開發者來說這件事是非常麻煩、會忘記&難以察覺。
Smart Pointer:和Naked Pointer相反,擁有Reference Counting的資訊,讓一個物件被SmartPointer控制,知道每個指向他的Reference。(簡單來說就是Memory Management)
Reference Counting:
在DirectX的物件實做COM時,裡面用到的Reference Counting,AddRef()和Release():
1: MySound *sound = new MySound;
2: sound->AddRef();Reference Counting裡面存有 interge counter在呼叫AddRef()時,interge counter會+1,呼叫Release()則是減少 reference counter並當counter變成0的時候會摧毀物件。
1: for(int i =0; i<soundNum;++i)
2: { 3: MySound *s = GetSoundPointer(i); 4: s->AddRef(); 5: 6: DoFunction();7: if(s->IsPlaying())
8: { 9: Do(); 10: } 11: s->Release(); 12: }如果DoFunction()時做遊戲邏輯後,不小心刪除 MySound物件,在這個loop也可能會執行成功即使MySound的Pointer已指向 unallocated memory,這很容易產生 memory corruption。
Smart Pointer:
SmartPtr.h:
1: #ifndef _SMARTPTR_H_
2: #define _SMARTPTR_H_
3: template<class T> class SmartPtr;
4: 5: template<class T>class IRefCount{
6: friend class SmartPtr<T>;
7: protected:
8: virtual void AddRef() = 0;
9: virtual void Release() = 0;
10: virtual T * GetPtr() const =0;
11: }; 12: 13: template<class T> class IRefCountImpl : public IRefCount<T>
14: {15: private :
16: int m_Count;
17: protected:
18: virtual void AddRef(){m_Count++;}
19: virtual void Release()
20: { 21: assert(m_Count > =0); 22: m_Count--;23: if(m_Count <=0)
24: Destory(); 25: }26: virtual T *GetPtr() const{return((T*)this);}
27: virtual void Destory(){if(GetPtr()!=NULL) delete GetPtr();}
28: IRefCountImpl(){m_Count=0;} 29: } 30: 31: template<class T> class SmartPtr
32: {33: private:
34: IRefCount<T> *m_RefCount; 35: 36: class RefCounter :public IRefCountImpl<T>
37: {38: private:
39: T *m_Ptr;40: protected:
41: virtual T* GetPtr() const {return m_Ptr;}
42: virtual void Destory(){delete this;}
43: public:
44: RefCounter(T *ptr){m_Ptr = ptr;}45: virtual ~RefCounter(){IRefCountImpl<T>::Destory();}
46: };47: void Assign(void * ptr)
48: {49: if(ptr==NULL)
50: Assign((IRefCount<T> *)NULL);51: else
52: Assign(new RefCounter(static_cast<T *>(ptr)));
53: }54: void Assign(IRefCount<T> *refcount)
55: {56: if(refcount!=NULL)
57: refcount->AddRef(); 58: IRefCount<T> *oldref = m_RefCount; 59: m_RefCount = refcount;60: if(oldref != NULL)
61: oldref->Release(); 62: }63: public:
64: SmartPtr() {m_RefCount = NULL;} 65: SmartPtr(T *ptr {m_RefCount= NULL;Assign(ptr);}66: SmartPtr(const SmartPtr &sp){m_RefCount = NULL;Assign(sp.m_RefCount);}
67: virtual ~SmartPtr(){Assign((IRefCount<T> *)NULL);
68: 69: T *GetPtr() const{return (m_RefCount==NULL)?NULL:m_RefCount->GetPtr();}
70: 71: SmartPtr& operator = (const SmartPtr &s[){Assign(sp.m_RefCount); return *this;
72: SmartPtr& operator = (T * ptr){Assign(ptr);return *this;}
73: T * operator ->() {assert(GetPtr() != NULL);return GetPtr();}
74: operator T* () const {return GetPtr();}
75: 76: bool operator !() {return GetPtr()== NULL;}
77: bool operator ==(const SmartPtr &sp){return GetPtr()==sp.GetPtr();}
78: bool operator !=(const SmartPtr &sp){return GetPtr()!=sp.GetPtr();}
79: };80: #endif
Example to use SmartPointer:
SmartPtr.cpp
1: #include "stdafx.h"
2: #include "assert.h"
3: #include "SmartPtr.h"
4: 5: class CMyObject
6: {7: char *name;
8: public:
9: CMyObject(char *aname){name = aname;printf("create %s\n",name);}
10: virtual ~CMyObject(){printf("delete %s\n",name);}
11: void print(){printf("print %s\n",name);}
12: }; 13: 14: SmartPtr<CMyObject> f1(char *name)
15: {16: return SmartPtr<CMyObject>(new CMyObject(name));
17: }18: void f2(CMyObject *o)
19: {20: printf("(print from a function)");
21: o->print(); 22: } 23: 24: int main(void)
25: {26: SmartPtr<CMyObject> ptr1(new CMyObject("1"));
27: SmartPtr<CMyObject> ptr2 = new CMyObject("2");
28: 29: ptr1 = ptr2; //destory object 1
30: ptr2 =f1("3"); // used as a return value
31: ptr2 = NULL; //destory object 3
32: f2(ptr1); 33: 34: //Bad Usageage
35: //CMyObject o1;
36: //ptr1 = &o1; //It's on stack
37: 38: //CMyObject *o2 = new CMyObject;
39: //ptr1 =o2;
40: //ptr2 = o2; //Don't ! unless CMyObject implements IRefCount
41: //try to use ptr1= ptr2 instead.it's always safe;
42: 43: SmartPtr<int> a (new int);
44: SmartPtr<int> b(new int);
45: *a=5; 46: *b =647: return
48: }Template類別用Overloaded assignment operators去呼叫AddRef()&Release()。
SmartPointer優點:
1.不用擔心Memory leak
Reference: Game Coding Complete.
No comments:
Post a Comment