Thank you for your replies.
@jRaskell
Indeed, this could cause a delay in developing the actual game, but since I'm not programming on a deadline, but rather as a preparation for "official" learning and as a hobby, I guess that pretty much everything I code (or try to code) can be considered an academic pursuit. :)
And by the way, I assume you deduced from my previous answer that a single map would do the trick, but it doesn't, there are some features I want to have which a simple map can't handle. Not to mention my system actually
uses both an std::map and an std::vector internally.
@kbw
You assume that a handle with value zero is invalid. that isn't the case. |
Actually, my first model of the CHandle class featured (along with the index) a private bool member mValid, which could only be set and reset by the manager class, to ensure the handle was valid. But I figured that that extra member wasn't necessary if I established that an index of zero correspondes an invalid handle i.e. a null handle, and that's what I did.
Take a look at the following code from my manager class (line 71 of the code I originally posted):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
CHandle<Data> Handle;
if( mFreeIndexes.empty() )
{
mInstances.push_back( &Instance );
Handle.Assign( mInstances.size() );
}
else
{
mInstances[ mFreeIndexes.top() ] = &Instance;
Handle.Assign( ( mFreeIndexes.top()+1 ) );
mFreeIndexes.pop();
}
| |
As you can see, the value I'm assigning to Handle is the index of the stored data
+1 thereby "reserving" zero for the null handle.
Why does the Manager know how to dereference a handle? Surely only a handle can do that. |
I'm not sure I fully understand what you mean, maybe the definition of dereference which I'm using differs from yours. The manager is the one who dereferences the handle because it is the one who can actually access the data. However, I've designed this system so that new types, say a CImageHandle, can contact their manager, say Image Handle Manager (a singleton) and directly access the data they point at.
And you are right, I should have posted some sort of example usage, and for that I apologize.
Here's the piece of code I've been using to debug the system. It uses a dummy resource class, CImage, to exemplify what I expect to get out of this system.
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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
#include <iostream>
#include <string>
#include "CHandleManager.hpp"
#include "CHandleMapper.hpp"
#include "Singleton.hpp"
class CImage
{
public:
CImage();
~CImage();
bool Load( const std::string & Name );
void Unload();
const std::string & GetName() { return mName; }
private:
std::string mName;
};
CImage::CImage()
{
}
CImage::~CImage()
{
}
bool CImage::Load( const std::string & Name )
{
mName = Name;
return true;
}
void CImage::Unload()
{
}
using namespace std;
typedef CHandleManager<CImage> ImageHandleManager;
typedef CHandleMapper<CImage> ImageHandleMapper;
ImageHandleManager & ImgHndMgr = Singleton<ImageHandleManager>::GetInstance();
ImageHandleMapper & ImgHndMpr = Singleton<ImageHandleMapper>::GetInstance();
class CImageHandle
{
public:
CImageHandle(const CHandle<CImage> & Handle) : mHandle( Handle ) { }
CImageHandle & operator=(const CHandle<CImage> & Handle) { mHandle = Handle; return ( *this ); }
CImage * operator*() { return ImgHndMgr.Dereference( mHandle ); }
CImage * operator->() { return ImgHndMgr.Dereference( mHandle ); }
operator CHandle<CImage>() { return mHandle; }
operator CHandle<CImage>&() { return mHandle; }
private:
CHandle<CImage> mHandle;
};
int main()
{
CImage AwesomeImage, CoolImage, DecentImage, BadImage, TerribleImage;
AwesomeImage.Load( "./gfx/Awesome.png" );
CoolImage.Load( "./gfx/Cool.png" );
DecentImage.Load( "./gfx/Decent.png" );
BadImage.Load( "./gfx/Bad.png" );
TerribleImage.Load( "./gfx/Terrible.png" );
CImageHandle ImgHandle1 = ImgHndMgr.Insert( AwesomeImage );
CImageHandle ImgHandle2 = ImgHndMgr.Insert( CoolImage );
CImageHandle ImgHandle3 = ImgHndMgr.Insert( DecentImage );
CImageHandle ImgHandle4 = ImgHndMgr.Insert( BadImage );
CImageHandle ImgHandle5 = ImgHndMgr.Insert( TerribleImage );
cout << ImgHandle1->GetName() << endl;
ImgHndMpr.Insert( "Img_Awesome", ImgHandle1 );
ImgHndMpr.Insert( "Img_Cool", ImgHandle2 );
ImgHndMpr.Insert( "Img_Decent", ImgHandle3 );
ImgHndMpr.Insert( "Img_Bad", ImgHandle4 );
ImgHndMpr.Insert( "Img_Terrible", ImgHandle5 );
CImageHandle Temp = ImgHndMpr.Get( "Img_Terrible" );
cout << Temp->GetName() << endl;
ImgHndMgr.Remove( Temp );
CImage AwfulImage;
AwfulImage.Load( "./gfx/Awfull.png" );
ImgHandle5 = ImgHndMgr.Insert( AwfulImage );
cout << ImgHandle5->GetName() << endl;
return 0;
}
| |
The idea is to have an actual ImageManager (instead of a typedef) which would have a HandleManager for Image Handles, but I think you get how I plan to use it from this. Ownership, Loading/Unloading would be some of the responsibilities of this ImageManager class.
Again, if you spot any bug or design flaw, please do post back!
Sorry about the long post!
Best Regards,
~Deimos