I've been trying to find a way to implement an object pool in my project. I've found a few examples on the internet and most of them use std::lists and an example of it in a book; Game development patterns and best practices that also use std::list.
I've been told, however, that it's kind of pointless to use lists for object pooling since returning an object back to the pool means that memory has to be allocated again.
I have also seen people utilize std::stack but I assume the same issue exists.
Here's the code I made for an object pool class following the book's example:
/* This object has only an int data type (value).
One method to se it and another one to print it. */
class Object
{
public:
Object()
{
SetValue();
std::cout << "Constructed/Reset." << std::endl;
}
// Copy constructor
Object( Object& other )
{
this->mValue = other.mValue;
std::cout << "Constructed." << std::endl;
}
~Object()
{
std::cout << "Destroyed." << std::endl;
}
void SetValue( int val = -1 )
{
mValue = val;
}
void PrintValue()
{
std::cout << this->mValue << std::endl;
}
private:
int mValue;
};
class Pool
{
public:
Pool()
{
std::cout << "Pool created!\n";
}
~Pool()
{
std::cout << "Pool destroyed!\n";
}
void Fill( int size )
{
for( int i = 0; i < size; i++ )
{
Object* obj = new Object();
pool.push_back( obj );
}
std::cout << "Objects created!" << "\nObjects in pool: "
<< pool.size() << std::endl;
}
Object* AquireObject()
{
if( !pool.empty() )
{
Object* obj = pool.back();
pool.pop_back();
std::cout << "Object aquired!"
<< "\nNumber of objects in pool: " << pool.size() << std::endl;
return obj;
}
else
{
std::cout << "Object created and aquired!"
<< "\nNumber of objects in pool: " << pool.size() << std::endl;
return new Object();
}
}
void ReleaseObject( Object* returningObject )
{
returningObject->SetValue();
pool.push_back( returningObject );
std::cout << "Object returned to the pool!"
<< "\nNumber of objects in pool: " << pool.size() << std::endl;
}
void Clear()
{
while( !pool.empty() )
{
Object* obj = pool.back();
pool.pop_back();
delete obj;
}
std::cout << "Objects deleted!"
<< "\nNumber of objects in pool: " << pool.size() << std::endl;
}
private:
std::list<Object*> pool;
};
I also made a slightly different version that uses unique pointers instead:
/* This object has only an int data type (value).
One method to se it and another one to print it. */
class Object
{
public:
Object()
{
SetValue();
std::cout << "Constructed/Reset." << std::endl;
}
// Copy constructor
Object( Object& other )
{
this->mValue = other.mValue;
std::cout << "Constructed." << std::endl;
}
~Object()
{
std::cout << "Destroyed." << std::endl;
}
void SetValue( int val = -1 )
{
mValue = val;
}
void PrintValue()
{
std::cout << this->mValue << std::endl;
}
private:
int mValue;
};
// Object pool using std::list
class Pool
{
public:
Pool() = default;
~Pool() = default;
/* Fills the pool (list) with a given size using an Object class (previously defined)
as a reference using its copy constructor.*/
void Fill( int size, Object* obj )
{
for( int i = 0; i < size; i++ )
{
std::unique_ptr<Object> object = std::make_unique<Object>( *obj );
pool.push_back( std::move( object ) );
}
}
// Clears all items in the list.
void PoolIsClosed()
{
pool.clear();
}
// Returns an instance of an object within the list.
std::unique_ptr<Object> GetObject()
{
if( !pool.empty() )
{
std::unique_ptr<Object> object = std::move( pool.front() );
pool.pop_front();
std::cout << "Object retrieved." << "\nObjects in pool: "
<< pool.size() << std::endl;
return object;
}
else
{
/* "WARNING: NOT ALL CONTROL PATHS RETURN A VALUE." */
std::cout << "Pool is empty." << std::endl;
}
}
// Returns an instance back to the object list.
void returnToPool( std::unique_ptr<Object> returningObject )
{
pool.push_back( std::move( returningObject ) );
std::cout << "Object returned." << "\nObjects in pool: "
<< pool.size() << std::endl;
}
private:
std::list<std::unique_ptr<Object>> pool;
};
I want to know if an implementation like this is really pointless and if so, is there a simple-ish way to implement a basic object pool class?
I know that the boost library has its own implementation of an object pool... Has anyone of you used it before? I would love to know more about it, is it hard to use?..
I also found this object pool library: https://github.com/mrDIMAS/SmartPool which looks promising and kind of easy to use but I don't know how it works under the hood, it was a bit complicated for me to understand. Any opinions about this one?