當使用到 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 =6
47: return
48: }
Template類別用Overloaded assignment operators去呼叫AddRef()&Release()。
SmartPointer優點:
1.不用擔心Memory leak
Reference: Game Coding Complete.
No comments:
Post a Comment