BOOKS i'm reading |
Enhance your dynamic memory allocation in C++ with an undocumented MFC class (CFixedAlloc)Contents
Anatomy of CFixedAllocLet's start by viewing the class declaration:
class CFixedAlloc { // Constructors public: CFixedAlloc(UINT nAllocSize, UINT nBlockSize = 64); // Attributes UINT GetAllocSize() { return m_nAllocSize; } // Operations public: void* Alloc(); // return a chunk of // memory of nAllocSize void Free(void* p); // free chunk of memory // returned from Alloc void FreeAll(); // free everything allocated // from this allocator // Implementation public: ~CFixedAlloc(); protected: struct CNode { CNode* pNext; // only valid when in // free list }; UINT m_nAllocSize; // size of each block // from Alloc UINT m_nBlockSize; // number of blocks to // get at a time CPlex* m_pBlocks; // linked list of blocks // (is nBlocks*nAllocSize) CNode* m_pNodeFree; // first free node // (NULL if no free nodes) CRITICAL_SECTION m_protect; }; As you can see, it is a very simple class. The first thing that we can notice is that the class provides thread safety with a critical section. Next, m_allocSize*m_blockSize+sizeof(CPlex) If you are interested in knowing more about void* CFixedAlloc::Alloc() { EnterCriticalSection(&m_protect); if (m_pNodeFree == NULL) { CPlex* pNewBlock = NULL; TRY { // add another block pNewBlock = CPlex::Create(m_pBlocks, m_nBlockSize, m_nAllocSize); } CATCH_ALL(e) { LeaveCriticalSection(&m_protect); THROW_LAST(); } END_CATCH_ALL // chain them into free list CNode* pNode = (CNode*)pNewBlock->data(); // free in reverse order to make it // easier to debug (BYTE*&)pNode += (m_nAllocSize * m_nBlockSize) - m_nAllocSize; for (int i = m_nBlockSize-1; i >= 0; i--, (BYTE*&)pNode -= m_nAllocSize) { pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; } } ASSERT(m_pNodeFree != NULL); // we must have something // remove the first available node from the free list void* pNode = m_pNodeFree; m_pNodeFree = m_pNodeFree->pNext; LeaveCriticalSection(&m_protect); return pNode; } void CFixedAlloc::Free(void* p) { if (p != NULL) { EnterCriticalSection(&m_protect); // simply return the node to the free list CNode* pNode = (CNode*)p; pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; LeaveCriticalSection(&m_protect); } } In ASSERT(nAllocSize >= sizeof(CNode)); If you want to see the CRT code, with a glimpse of an eye, you can tell that And finally, let me introduce to you macros that help to use // DECLARE_FIXED_ALLOC -- used in class definition #define DECLARE_FIXED_ALLOC(class_name) \ public: \ void* operator new(size_t size) \ { \ ASSERT(size == s_alloc.GetAllocSize()); \ UNUSED(size); \ return s_alloc.Alloc(); \ } \ void* operator new(size_t, void* p) \ { return p; } \ void operator delete(void* p) { s_alloc.Free(p); } \ void* operator new(size_t size, LPCSTR, int) \ { \ ASSERT(size == s_alloc.GetAllocSize()); \ UNUSED(size); \ return s_alloc.Alloc(); \ } \ protected: \ static CFixedAlloc s_alloc \ // IMPLEMENT_FIXED_ALLOC -- used in class implementation file #define IMPLEMENT_FIXED_ALLOC(class_name, block_size) \ CFixedAlloc class_name::s_alloc(sizeof(class_name), block_size) \ The |