stl allocator实现代码

    技术2024-10-10  57

    最近研究了一下stl的内存分配器,现在整理了一份关于分配器的代码, 希望对大家有帮助!!

     

    首先是动态内存分配器,代码如下:

     

    #ifndef POOL_H_INCLUDED_GF#define POOL_H_INCLUDED_GF

    //// 大块内存分配器//

    #ifdef _WIN32#pragma warning(push)#pragma warning(disable:4018) // signed/unsigned mismatch#pragma warning(disable:4290) // exception spec ignored#endif

    #include <exception>#include <list>#include <algorithm>#include <iostream>#include "noncopy.h"

    class CChunkAllocator : public Gavin::CNonCopy{ class logic_error : public std::exception { public:  logic_error(const char *what):what_(what){}  const char* what() { return what_; }

     private:  const char* what_; };

     // 释放仿函数, Skiller()就是生成一个临时的对象 struct SKiller {  void operator()(char *p)  {   delete [] p;  } };

     enum pool_defaults {  init_size = 0xfffff,  min_size = 0xf };

    public: // 分配内存,并注册到系统中去 CChunkAllocator(size_t size = init_size) : m_nSize(size) {  if((m_nSize - BLOCK_SZIE) < min_size)   {   throw logic_error("Initial pool size too small");  }

      char* poBlock = new char[m_nSize];  if (!poBlock)  {   throw std::bad_alloc();  }

      m_listMemPool.push_back(poBlock);  // 资源保存  m_poMemBlocks = reinterpret_cast<SBlockHead*>(poBlock);  // 第一个block块  m_poMemBlocks->m_poPrev = 0;  m_poMemBlocks->m_poNext = 0;  m_poMemBlocks->m_nFree = 1;  m_poMemBlocks->m_nSize = (m_nSize - BLOCK_SZIE); } ~CChunkAllocator() {  std::for_each(m_listMemPool.begin(), m_listMemPool.end(), SKiller()); }

     // 分配size大小的内存 void* allocate(size_t size) {  if(size > (m_nSize - BLOCK_SZIE))   {   throw std::bad_alloc();  }

      // 如果没有足够的空间,就首先分配空间  SBlockHead* poBlock = m_poMemBlocks;  while(1)  {   // 这里好像会有死循环,这里似乎要保证申请的内存小于m_nSize的大小   while(!poBlock->m_nFree)   {    if(!poBlock->m_poNext)     {     grow(poBlock);    }    poBlock = poBlock->m_poNext;   }

       if(poBlock->m_nSize < size)    {    continue;   }

       break;  }

      if(poBlock->m_nSize - size < 2 * BLOCK_SZIE) // 内存不足,直接浪费了?  {   poBlock->m_nFree = 0;

       // 前面加了一个SBlockInfo的头,返回容易处理,注意这里的位置关系   return reinterpret_cast<char *>(poBlock) + BLOCK_SZIE;  }  else  {   // 把剩余的内存保存起来   SBlockHead * poLeftBlock = reinterpret_cast<SBlockHead *>(reinterpret_cast<char *>(poBlock)     + size + BLOCK_SZIE);   if(poBlock->m_poNext)   {    poBlock->m_poNext->m_poPrev = poLeftBlock;   }   poLeftBlock->m_poNext = poBlock->m_poNext;   poBlock->m_poNext = poLeftBlock;   poLeftBlock->m_poPrev = poBlock;   poBlock->m_nFree = 0;   poLeftBlock->m_nSize = poBlock->m_nSize - size - BLOCK_SZIE;   poBlock->m_nSize = size;   poLeftBlock->m_nFree = 1;   return reinterpret_cast<char *>(poBlock) + BLOCK_SZIE;  }       }

     // 释放内存,poMem是从allocate函数中分配的 void deallocate(void* poMem, size_t nSize = 0) {  if(!poMem)   {   return;  }  // 得到原来的SBlockHead*  SBlockHead* poBlock = reinterpret_cast<SBlockHead *>(static_cast<char*>(poMem) - BLOCK_SZIE);  if(poBlock->m_poPrev && poBlock->m_poNext)  {   if(poBlock->m_poPrev->m_nFree && poBlock->m_poNext->m_nFree)   {    poBlock->m_poPrev->m_nSize += poBlock->m_nSize + poBlock->m_poNext->m_nSize + 2 * BLOCK_SZIE;    poBlock->m_poPrev->m_poNext = poBlock->m_poNext->m_poNext;    if(poBlock->m_poNext->m_poNext)    {     poBlock->m_poNext->m_poNext->m_poPrev = poBlock->m_poPrev;    }    return;   }  }

      if(poBlock->m_poPrev)  {   // 合并内存   if(poBlock->m_poPrev->m_nFree)   {    poBlock->m_poPrev->m_nSize += (poBlock->m_nSize + BLOCK_SZIE);    poBlock->m_poPrev->m_poNext = poBlock->m_poNext;    if(poBlock->m_poNext)     {     poBlock->m_poNext->m_poPrev = poBlock->m_poPrev;    }    poBlock->m_nFree= 1;    return;   }  }

      if(poBlock->m_poNext)  {   // 合并内存   if(poBlock->m_poNext->m_nFree)   {    poBlock->m_nSize += (poBlock->m_poNext->m_nSize + BLOCK_SZIE);    poBlock->m_poNext = poBlock->m_poNext->m_poNext;    if(poBlock->m_poNext)    {     poBlock->m_poNext->m_poPrev = poBlock;    }    poBlock->m_nFree= 1;    return;   }  }

      poBlock->m_nFree = 1; }

     // 显示内存使用情况 void dump() {  using namespace std;  SBlockHead *b = m_poMemBlocks;  while(1)  {   cout << "Size=" << b->m_nSize << ", free=" << b->m_nFree <<    ", prev=" << b->m_poPrev << ", next=" << b->m_poNext << endl;   if(b->m_poNext)    {       b = b->m_poNext;   }   else   {    break;   }  } }

    protected: // 释放内存 static void kill(char* p)  {   delete [] p; }

     // 增长内存一块m_nSize的内存,并加入到poOldBlock后面 void grow(SBlockHead* poOldBlock) {  SBlockHead* poNewBlock = NULL;  char* poNewMem = new char[m_nSize];  if (!poNewMem)  {   throw std::bad_alloc();  }  m_listMemPool.push_back(poNewMem);  poNewBlock = reinterpret_cast<SBlockHead*>(poNewMem);  poNewBlock->m_poPrev = poOldBlock;  poNewBlock->m_poNext = NULL;  poNewBlock->m_nFree = 1;  poNewBlock->m_nSize = (m_nSize - BLOCK_SZIE);  poOldBlock->m_poNext = poNewBlock; }

    private: size_t m_nSize; std::list<char *> m_listMemPool;

     // 数据块节点 struct SBlockHead {  SBlockHead* m_poPrev;   // prev指针  SBlockHead* m_poNext;   // next指针  size_t m_nSize;         // 块大小  int m_nFree;            // 剩余数量

      SBlockHead(SBlockHead* prev, SBlockHead* next, size_t size, int free) :   m_poPrev(prev), m_poNext(next), m_nSize(size), m_nFree(free)  {  }  ~SBlockHead()  {  } };#define  BLOCK_SZIE sizeof(SBlockHead) SBlockHead* m_poMemBlocks;};

    #ifdef _WIN32#pragma warning(pop)#endif

    #endif

     

    根据上面的内存管理器而来的stl分配器(allocator0如下:

     

    #ifndef POOL_ALLOCATOR_H_INCLUDED_GF#define POOL_ALLOCATOR_H_INCLUDED_GF

    #include "pool.h"

    // 申明template <typename T>class pool_allocator;

    // 偏特化voidtemplate <> class pool_allocator<void>{public:    typedef void* pointer;    typedef const void* const_pointer;    typedef void value_type;

        template <class U>     struct rebind { typedef pool_allocator<U> other; };};   

    namespace pool_alloc{    inline void destruct(char *) {}    inline void destruct(wchar_t*) {}    template <typename T>     inline void destruct(T *t) { t->~T(); }}    template <typename T>class pool_allocator{public:    typedef size_t size_type;    typedef ptrdiff_t difference_type;    typedef T* pointer;    typedef const T* const_pointer;    typedef T& reference;    typedef const T& const_reference;    typedef T value_type;

        template <class U>     struct rebind  {   typedef pool_allocator<U> other;  };

        pool_allocator() {}    pointer address(reference x) const { return &x; }    const_pointer address(const_reference x) const { return &x; }

     // 分配函数    pointer allocate(size_type size, pool_allocator<void>::const_pointer hint = 0)    {        return static_cast<pointer>(mem_.allocate(size * sizeof(T)));    }

        // for Dinkumware:    char *_Charalloc(size_type n) { return static_cast<char*>(mem_.allocate(n)); }    // end Dinkumware

        template <class U> pool_allocator(const pool_allocator<U>&){}

     // 释放内存    void deallocate(pointer p, size_type n)    {        mem_.deallocate(p, n);    }    void deallocate(void* p, size_type n)    {        mem_.deallocate(p, n);    }

        size_type max_size() const throw() { return size_t(-1) / sizeof(value_type); }

        void construct(pointer p, const T& val)    {        new(static_cast<void*>(p)) T(val);    }

        void construct(pointer p)    {        new(static_cast<void*>(p)) T();    }

        void destroy(pointer p) { pool_alloc::destruct(p); }    static void dump(){ mem_.dump(); };

    private:    static CChunkAllocator mem_;};

    template <typename T> CChunkAllocator pool_allocator<T>::mem_;

    template <typename T, typename U>inline bool operator == (const pool_allocator<T>&, const pool_allocator<U>) { return true; }

    template <typename T, typename U>inline bool operator != (const pool_allocator<T>&, const pool_allocator<U>) { return false; }

     

    #endif

    最新回复(0)