stl allocator实现代码

来源:互联网 发布:国际大数据医疗公司 编辑:程序博客网 时间:2024/06/06 11:36

最近研究了一下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;

// 偏特化void
template <> 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