Hey again,
After trying to produce an actual game using my first game engine, I reached the conclusion that it sucked. It's mostly because I didn't pay much attention to memory management when I was developing it, I relied too much on our friends new and delete. As a result, I got some nice segfaults in which I lost too much time fixing. However, I'm happy about what I learnt. :)
Moving on, I decided to start out fresh and before any coding I read a bit on Design Patterns, and I feel that made me think slightly differently about problems and it also made some things quite clearer. :) Now, onto the matter for which I'm here...These are some classes which will be used by my future games. I tried to make them as clean as possible but since all my games will be depending on them I want to make sure that everything is OK. Any suggestion, remark, comment would be greatly appreciated. :)
They are:
An interface for all reference-counted classes;
A smart-pointer;
A singleton interface.
Here's the code:
1 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
|
#ifndef I_REF_COUNTED_H
#define I_REF_COUNTED_H
class IRefCounted
{
public:
IRefCounted() : m_RefCount(0) {}
virtual ~IRefCounted() {}
void Grab() { IncRef(this); }
void Release() { DecRef(this); }
private:
IRefCounted(const IRefCounted& obj) {};
static void IncRef(IRefCounted *pObj)
{
if(pObj)
{
pObj->m_RefCount++;
}
}
static void DecRef(IRefCounted *pObj)
{
if(pObj)
{
pObj->m_RefCount--;
if(pObj->m_RefCount <= 0)
{
delete pObj;
pObj = NULL;
}
}
}
int m_RefCount;
};
#endif
| |
1 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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
#ifndef C_SMART_POINTER_H
#define C_SMART_POINTER_H
template<class T>
class CSmartPointer
{
public:
CSmartPointer() : m_pT(NULL) {}
CSmartPointer(T* pT) : m_pT(pT) { GrabRef(); }
CSmartPointer(const CSmartPointer& ptr) : m_pT(ptr.m_pT) { GrabRef(); }
~CSmartPointer() { ReleaseRef(); }
CSmartPointer& operator=(T* pT)
{
if(IsNull())
{
if(pT)
{
//The previous pointer was NULL, so no need for ReleaseRef()
//Assign pointer and grab reference
m_pT = pT;
GrabRef();
}
}
else
{
//The previous pointer is no longer in use
ReleaseRef();
//Assign new pointer and grab a new Reference
m_pT = pT;
//GrabRef is "NULL-safe"
GrabRef();
}
//So as to allow multiple assignments ptr1 = ptr2 = pr3...
return *this;
}
//Only difference is the need to access to CSmartPointer's internal pointer
CSmartPointer& operator=(const CSmartPointer& ptr)
{
if(IsNull())
{
if(ptr.pT)
{
m_pT = ptr.pT;
GrabRef();
}
}
else
{
ReleaseRef();
m_pT = ptr.pT;
GrabRef();
}
}
//Checking for NULL and equality
bool operator!() { return m_pT == NULL; }
bool operator==(const T* pT) { return pT == m_pT; }
bool operator==(const CSmartPointer& ptr) { return ptr.m_pT == m_pT; }
//Simulating a "raw" pointer usage trough operator overloading
T* operator*(){ return m_pT; }
T* operator->() { return m_pT; }
private:
void GrabRef()
{
if(m_pT)
m_pT->Grab();
}
void ReleaseRef()
{
if(m_pT)
m_pT->Release();
}
bool IsNull() { return m_pT == NULL; }
T* m_pT;
};
#endif
| |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
#ifndef I_SINGLETON_H
#define I_SINGLETON_H
#include "IRefCounted.h"
#include "CSmartPointer.h"
template<class T>
class ISingleton : public IRefCounted
{
public:
virtual ~ISingleton() {}
static T* GetInstance() { if(!m_pInstance) m_pInstance = new T; return *m_pInstance; }
protected:
ISingleton() {}
private:
static CSmartPointer<T> m_pInstance;
};
template<class T>
CSmartPointer<T> ISingleton<T>::m_pInstance = NULL;
#endif
| |
Sorry about pasting all this stuff here. :)
Thanks in advance and Best Regards,
Deimos