As part of a little test I have written a pooled object allocator. This is the first time I have written something like this and I quite enjoyed it. I dare say that I have probably fallen foul of some of the little gotchas in developing one of these but hopefully on my next pass or if I use it a little they may become apparent. Overall though for a little exercise I learned a little and wasn't a bad use of a spare hour or so.
THE CODE
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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | #include <utility> //std::forward #include <stack> //std::stack template<class inputType> class SimplePool { public: SimplePool(unsigned int _capacity, int _overrideTypeSize = -1) : m_allocatedCount(0u), m_rawMemory(NULL), m_endOfMemory(NULL), m_typeSize(0), m_maxCount(0) { // This override type size might sound odd, but can be useful if you need to add padding but don't want to add it to the class. m_typeSize = _overrideTypeSize != -1 ? _overrideTypeSize : sizeof(inputType); // Assign the base memory pool we will allocate from. m_rawMemory = static_cast<inputType*>( malloc(_capacity * m_typeSize) ); //Checking assignment was possible. if (m_rawMemory) { m_endOfMemory = m_rawMemory + _capacity; m_maxCount = _capacity; //We could also use a vector and reserve all the memory ahead of time and keep track of where we are in it //but using a stack for simplicities sake. for (unsigned int i = 0; i < m_maxCount; i++) { m_locations.push(m_rawMemory + i); } } } ~SimplePool() { // Freeing all the assigned memory. free(m_rawMemory); // Cleaning up. You never know this pool might be in a pool. m_rawMemory = NULL; m_endOfMemory = NULL; m_allocatedCount = 0u; m_typeSize = 0u; m_maxCount = 0u; } bool IsInitialised() { //Check to see if the pool is active. return m_rawMemory != NULL; } bool Allocate(inputType** _inputPointer) { //Check we have any room. if (m_allocatedCount < m_maxCount) { //If we have any free slots. if (m_locations.size()) { //Always taking from the top of the pile - hoping the memory is still hot. (*_inputPointer) = m_locations.top(); m_locations.pop(); //increment the in use count. ++m_allocatedCount; return true; } } return false; } //Separate Allocation when allocating something that needs a constructor. template <typename ...Args> bool Allocate_Construct(inputType** _inputPointer, Args&&... args) { //Check we have any room. if (m_allocatedCount < m_maxCount) { //If we have any free slots. if (m_locations.size()) { //Always taking from the top of the pile - hoping the memory is still hot. inputType* addressPtr = m_locations.top(); *_inputPointer = new((addressPtr)) inputType(std::forward<Args>(args)...); m_locations.pop(); //increment the in use count. ++m_allocatedCount; return true; } } return false; } bool Deallocate(inputType* _objectToRemove, bool _clear = false) { //Check the memory we are deleting is in the pool if ( (_objectToRemove > m_rawMemory) && (_objectToRemove < m_endOfMemory)) { if (_clear) { memset(_objectToRemove, 0, m_typeSize); } //Add deleted object back to the list. m_locations.push(_objectToRemove); --m_allocatedCount; return true; } return false; } bool Deallocate_Destruct(inputType* _objectToRemove, bool _clear = false) { //Check the memory we are deleting is in the pool if ((_objectToRemove > m_rawMemory) && (_objectToRemove < m_endOfMemory)) { //Call destructor allocated object. _objectToRemove->~inputType(); //Add deleted object back to the list. m_locations.push(_objectToRemove); --m_allocatedCount; return true; } return false; } inputType* m_rawMemory; inputType* m_endOfMemory; unsigned int m_allocatedCount; unsigned int m_typeSize; unsigned int m_maxCount; std::stack<inputType*> m_locations; }; int main() { SimplePool<unsigned int> pool(1024u); //Test! //-------------------------------------------------------- for (unsigned int i = 0; i < 1280; i++) { unsigned int* testOutput = 0; pool.Allocate_Construct(&testOutput, i); pool.Deallocate_Destruct(testOutput, true); //pool.Allocate(&testOutput); //pool.Deallocate(testOutput, true); } unsigned int* testdealloc = (unsigned int*)45656756765; pool.Deallocate(testdealloc, true); testdealloc = 0; pool.Deallocate(testdealloc, true); return 0; } |