For a hobby project, My aim is to design and implement a generic system for pooling an arbitrary class of object. I tried implementing it using templates.
This pool should support 4 actions:
“Create a pool”
“Allocate an object from this pool”
“Deallocate an object from this pool”
“Destroy this pool”
For sake of simplicity, there is no multi-threading involved.
- If I have to pool classes like this example, how do I do that?
typedef char ByteType;
typedef void* PointerType;
typedef char FixedStringType(256);
// A basic struct
struct Point
{
int x, y, z;
};
- Can someone please provide your thoughts/feedback on bugs and how to improve this code?
//ObjectPool.h
#pragma once
#include <vector>
#include <iostream>
const int g_MaxNumberOfObjectsInPool = 2;
template<typename T>
class DefaultAllocator {
public:
T* operator()() {
return new T{};
}
void operator()(T* p) {
delete p;
}
void reset() {
std::cout << "reset function called from default allocator" << std::endl;
}
};
template<typename T, typename AllocatorT=DefaultAllocator<T>>
class ObjectPool
{
struct ObjectInfo {
bool isInUse{};
T* ptrObject{};
};
static inline std::vector<ObjectInfo> poolObjects{};
static inline AllocatorT allocator{};
public:
static T* getObject() {
for (auto& currObj : poolObjects) {
if (!currObj.isInUse) {
currObj.isInUse = true;
std::cout << "Existing Object returned" << std::endl;
return currObj.ptrObject;
}
}
if (poolObjects.size() == g_MaxNumberOfObjectsInPool) {
std::cout << "Pool is full " << std::endl;
return nullptr;
}
std::cout << "Creating a new object" << std::endl;
//auto newObj = new T{};
auto newObj = allocator();
poolObjects.push_back({ true, newObj });
return newObj;
}
static void releaseObject(T* ptrSo) {
for (auto& currObj : poolObjects) {
if (currObj.ptrObject == ptrSo) {
currObj.isInUse = false;
return;
}
}
}
static void destroy() {
for (auto& currObj : poolObjects) {
if (currObj.isInUse) {
std::cout << "WARNING! this object is still in use" << std::endl;
}
allocator(currObj.ptrObject);
}
allocator.reset();
poolObjects.clear();
}
};
The main file looks like this:
#include "ObjectPool.h"
#include <iostream>
class PrivateClass {
PrivateClass() {
}
public:
void func() {
}
friend class PrivateAllocator;
};
class PrivateAllocator {
public:
PrivateClass* operator()() {
return new PrivateClass{};
}
void operator()(PrivateClass* p) {
delete p;
}
void reset() {
std::cout << "reset function called" << std::endl;
}
};
int main() {
using integer = ObjectPool<int>;
auto int1 = integer::getObject();
auto int2 = integer::getObject();
auto int3 = integer::getObject();
integer::releaseObject(int1);
auto int4 = integer::getObject();
integer::destroy();
return 0;
}