I've been reading about Memory Pools since I came across them in the book *Game Programming Complete 4th Edition*, and I decided to try and spin my own since I didn't quite understand how the one they presented in the book worked at the time. One thing I'm uncertain of is defining the deleter in the shared_ptr. I don't like using delegates when they aren't needed, but if I try to pass in the address to the function pointer as the deleter then the program will not compile. Memory chunks are stored in a singly-linked list, with the first N bytes of each entry in the list being a pointer to the next entry. While it's nifty using pointer majicks to store the pointer in the head of each chunk, it is scary to look at when you don't understand pointer-to-pointers (I know I didn't when I first tried to roll it out!). Any suggestions on changes? Improvements? Bugs I didn't see? #include <memory> namespace acorn { template<class Object> //An immutable memory pool does not grow or shrink in size. class ImmutableMemoryPool { typedef unsigned char byte; //A pointer to the block of data we will be allocating. byte* m_pBlock; //A pointer to the current chunk byte* m_pCurrentChunk; //A pointer to the last chunk byte* m_pLastChunk; unsigned int m_NumberOfChunks; unsigned int m_SizeOfChunk; unsigned int m_SizeOfChunkData; unsigned int m_SizeOfChunkHeader; unsigned int m_SizeOfBlock; public: ImmutableMemoryPool(unsigned int numberOfChunks) : m_NumberOfChunks(numberOfChunks), m_SizeOfChunkData(sizeof(Object)) { //Set the size of the header of each chunk m_SizeOfChunkHeader = sizeof(byte*); //Calculate the size of a whole chunk m_SizeOfChunk = m_SizeOfChunkHeader + m_SizeOfChunkData; //Calculate the size of the block of data m_SizeOfBlock = m_SizeOfChunk * m_NumberOfChunks; //Allocate a new block of memory m_pBlock = new byte[m_SizeOfBlock]; //Initialize the chunk header data InitializeHeaders(); //Set the current chunk pointer to point at the start of the block m_pCurrentChunk = m_pBlock; //Set the last chunk poitner to point at the last chunk m_pLastChunk = m_pBlock + m_SizeOfBlock - m_SizeOfChunk; } ~ImmutableMemoryPool() { delete[] m_pBlock; } //Places a chunk of memory back into the pool void Dealloc(Object* pData) { byte* pConvertedData = (byte*)pData; //Sure, call it on a nullptr - I don't care I'll just ignore it HA if (pConvertedData != nullptr) { //Make sure this pointer belongs to this pool if (pConvertedData < (m_pBlock + m_SizeOfBlock) && pConvertedData > m_pBlock) { //Get the header byte* pHeader = (byte*)pConvertedData - m_SizeOfChunkHeader; //Set the tail chunk to now point to this returned chunk instead of a nullptr byte** ppHeaderData = (byte**)m_pLastChunk; ppHeaderData[0] = pHeader; //Set the new tail as the returned chunk m_pLastChunk = pHeader; //Set the header data to point to a nullptr ppHeaderData = (byte**)pHeader; ppHeaderData[0] = nullptr; //If the current chunk was pointing to a nullptr, point it to the new tail instead if (m_pCurrentChunk == nullptr) { m_pCurrentChunk = pHeader; } } else { std::cout << "This data isn't mine!" << std::endl; } } } //Returns a single chunk of memory std::shared_ptr<Object> Alloc() { //If there are no available chunks, return a nullptr if (m_pCurrentChunk == nullptr) { std::cout << "Sorry! No more chunks to be given out. Come back later, but for now have this nullptr!" << std::endl; return nullptr; } //Get the pointer to the next chunk and set it to pNext byte** ppChunkHeaderData = (byte**)m_pCurrentChunk; byte* pNext = ppChunkHeaderData[0]; std::cout << (void*)m_pCurrentChunk << std::endl; std::cout << (void*)pNext << std::endl; //Get the data to return void* rawReturnData = m_pCurrentChunk + m_SizeOfChunkHeader; //Stick it into a shared pointer that automatically puts the object back into the pool when it is time. std::shared_ptr<Object> returnPtr((Object*)rawReturnData, [=](Object* pRawData){ Dealloc(pRawData); }); //Set the next chunk m_pCurrentChunk = pNext; return returnPtr; } protected: void InitializeHeaders() { byte* pHeader = nullptr; byte* pEnd = nullptr; byte* pNext = nullptr; byte** ppChunkHeader; //Set the header and end of the block pHeader = m_pBlock; pEnd = m_pBlock + m_SizeOfBlock; //Loop through and set the header of each chunk to point to the next chunk while (pHeader < pEnd) { pNext = pHeader + m_SizeOfChunk; ppChunkHeader = (byte**)pHeader; ppChunkHeader[0] = (pNext < pEnd ? pNext : nullptr); std::cout << "Header: " << (void*)pHeader << std::endl; std::cout << "Next: " << (void*)pNext << std::endl; pHeader = pNext; } std::cout << std::endl; } };