I was reading some gameprogrammingpatterns (awesome book, by the way, would recommend) and was very excited when I learned that unions are a thing that exists, so I decided to implement an object pool as outlined there.
I'm looking for a review of the usual culprits. Poor readability, not making use of standard library stuff/language features. But more than that, I'd love it if someone could point out how I could improve the access and removal algorithms, as well as an elegant way that I could have duplicates in the list.
What I mean by "doesn't allow duplicates", by the way, is that duplicates are considered equally, so if it's of type int
, and there are the values {1, 2, 3, 3, 4, 5}
in the pool, and you call removeObj(3)
, the first 3 that is come across will be "deleted", regardless of what you actually wanted.
#include <vector>
//Doesn't allow duplicates
//O(1) insertion
//O(n) removal
//O(n) access
template <class T>
class Pool
{
private:
struct Object
{
bool available;
union
{
T data;
Object* next;
}state;
};
int size = 0;
int numAlive = 0;
Object* nextAvailable = nullptr;
std::vector< Object > objs;
public:
Pool();
Pool(int size);
bool create(T newObj);
std::vector<T*> getAlive();
bool removeObj(T toDel);
};
template <class T>
Pool<T>::Pool()
{
}
template <class T>
Pool<T>::Pool(int size):size(size)
{
objs = std::vector< Object >(size);
//All are available
for(int i = 0; i < objs.size() - 1; i++)
{
objs[i].state.next = &objs[i+1];
}
objs[objs.size()-1].state.next = nullptr; //Last one terminates list
nextAvailable = &objs[0];
}
template <class T>
bool Pool<T>::create(T newObj)
{
if(nextAvailable == nullptr)
{
return false;
}
Object* newO = nextAvailable;
nextAvailable = nextAvailable->state.next;
newO->state.data = newObj;
newO->available = false;
numAlive++;
return true;
}
template <class T>
std::vector<T*> Pool<T>::getAlive()
{
std::vector<T*> avl = std::vector<T*>(numAlive);
int cnt = 0;
for(auto& o : objs)
{
if(!o.available)
{
avl.at(cnt++) = &(o.state.data);
}
}
return avl;
}
template <class T>
bool Pool<T>::removeObj(T toDel)
{
for(auto& ob: objs)
{
if(!ob.available && ob.state.data == toDel)
{
ob.state.next = nextAvailable;
ob.available = true;
nextAvailable = &ob;
numAlive--;
break;
}
}
}