This is a pretty easy technique to use. People do know about it, but many do not. The object manager keeps track of all your objects and allows you to retrieve them with using constant speed. It also makes sure that unused indices get used again. And it allows for tree like searches for the object.
Each object is given a handle. The handle is essentially an index into the object array store. Each object can optionally have a name. If you dont have the handle, you can find it by giving the name in O(log n) time.
Searches are not really necesasary, and if you want them, the only problem is that the time to remove an object will increase from O(1) to O(n). If that's not a problem, then searches can come in quite handy - especially for script/console systems.
Anyway, here's the code, with seaching commented out (not really coded)
#include <map>
#include <vector>
#include <iostream>
#include <string>
template< class T > class GenericManager;
template< class T >
class GenericHandle
{
friend class GenericManager<T>;
int m_index;
GenericHandle( int i )
: m_index(i)
{}
public:
GenericHandle()
: m_index(-1)
{}
bool IsValid() const
{
return m_index != -1;
}
};
template< class T >
class GenericManager
{
public:
typedef GenericHandle<T> Handle_t;
~GenericManager()
{
DestroyAll();
}
Handle_t Create( const T& prototype )
{
int idx = 0;
T* p = new T(prototype);
if( m_freeStore.size() )
{
idx = m_freeStore.back();
m_freeStore.pop_back();
m_objectStore[idx] = p;
}
else
{
idx = m_objectStore.size();
m_objectStore.push_back( p );
}
// m_mapStore[name] = idx;
// name would be an std::string parameter passed to this function as well
return Handle_t(idx);
}
void Destroy( Handle_t& h )
{
T* p = m_objectStore[h.m_index];
if( p )
{
delete p;
m_objectStore[h.m_index] = 0;
m_freeStore.push_back( h.m_index );
}
// Here's where things get slow if search capabilities are added
/*
iterator i = mapStore.begin()
for each i in map
if( i->second == h.m_index )
erase iterator i and break.
*/
h.m_index = -1;
}
void DestroyAll()
{
m_freeStore.clear();
for( std::size_t i = 0; i < m_objectStore.size(); ++i )
{
if( m_objectStore[i] )
{
delete m_objectStore[i];
}
}
m_objectStore.clear();
}
T* GetObject( Handle_t h ) const
{
if( !h.IsValid() )
return 0;
return m_objectStore[h.m_index];
}
/* Can have this function with search capabilities
Handle_t GetHandle( string name )
{
iterator i = map.find(name);
if( i != end ) return Handle_t(i->second);
return Handle_t(-1);
}
*/
private:
std::vector<int> m_freeStore;
std::vector<T*> m_objectStore;
// std::map<std::string, int> m_mapStore; // for searching
};
class SomeObject
{
std::string m_name;
public:
SomeObject( const std::string& name )
: m_name(name)
{}
SomeObject( const SomeObject& o )
{
m_name = o.m_name;
}
void Work()
{
std::cout << "I am " << m_name << std::endl;
}
};
int main()
{
typedef GenericManager<SomeObject> ObjMgr_t;
ObjMgr_t mgr;
ObjMgr_t::Handle_t h1 = mgr.Create( SomeObject("one") );
ObjMgr_t::Handle_t h2 = mgr.Create( SomeObject("two") );
ObjMgr_t::Handle_t h3 = mgr.Create( SomeObject("three") );
mgr.Destroy( h3 );
ObjMgr_t::Handle_t h4 = mgr.Create( SomeObject("four") );
if( mgr.GetObject( h1 ) )
mgr.GetObject( h1 )->Work();
if( mgr.GetObject( h2 ) )
mgr.GetObject( h2 )->Work();
if( mgr.GetObject( h3 ) )
mgr.GetObject( h3 )->Work();
if( mgr.GetObject( h4 ) )
mgr.GetObject( h4 )->Work();
/*
Seaching would allow for something like:
Handle = Manager.getHandle( "my object" );
*/
return 0;
}
Of course there is a lot that can and probably should be added to this class for official usage. First off, I've skipped error checking almost completley. Maybe there's a way to make the object deleting even faster. I've found ways that require the alteration of the GenericHandle structure, but I wanted to leave that the size of an int. IF anyone can see a different solution I'm all ears.












