小析Allocator


噢,是的,对初学者来说Allocator很神秘,希望我这篇文章能带你走进Allocator,看看它到底做了那些事。

1.初识allocator
对大多数人来数使用的IDE是vs.net.那么就看看vs.net这个版本的stl把。"代码面前,了无秘密",<xmemory>文件里,我们可以看到它的实现。

template<class _Ty>
class allocator: public _Allocator_base<_Ty>
{
...
};
class 里先定义了一些类型
 
        typedef _Ty value_type;
 typedef value_type _FARQ *pointer;
 typedef value_type _FARQ& reference;
 typedef const value_type _FARQ *const_pointer;
 typedef const value_type _FARQ& const_reference;

 typedef _SIZT size_type;
 typedef _PDFT difference_type;
接下去是一些借口函数

 template<class _Other>
  struct rebind
  { // convert an allocator<_Ty> to an allocator <_Other>
  typedef allocator<_Other> other;
  };

 pointer address(reference _Val) const
  { // return address of mutable _Val
  return (&_Val);
  }

 const_pointer address(const_reference _Val) const
  { // return address of nonmutable _Val
  return (&_Val);
  }

 allocator()
  { // construct default allocator (do nothing)
  }

 allocator(const allocator<_Ty>&)
  { // construct by copying (do nothing)
  }

 template<class _Other>
  allocator(const allocator<_Other>&)
  { // construct from a related allocator (do nothing)
  }

 template<class _Other>
  allocator<_Ty>& operator=(const allocator<_Other>&)
  { // assign from a related allocator (do nothing)
  return (*this);
  }

 void deallocate(pointer _Ptr, size_type)
  { // deallocate object at _Ptr, ignore size
  operator delete(_Ptr);
  }

 pointer allocate(size_type _Count)
  { // allocate array of _Count elements
  return (_Allocate(_Count, (pointer)0));
  }

 pointer allocate(size_type _Count, const void _FARQ *)
  { // allocate array of _Count elements, ignore hint
  return (allocate(_Count));
  }

 void construct(pointer _Ptr, const _Ty& _Val)
  { // construct object at _Ptr with value _Val
  _Construct(_Ptr, _Val);
  }

 void destroy(pointer _Ptr)
  { // destroy object at _Ptr
  _Destroy(_Ptr);
  }

 _SIZT max_size() const
  { // estimate maximum array size
  _SIZT _Count = (_SIZT)(-1) / sizeof (_Ty);
  return (0 < _Count ? _Count : 1);
  }

很清晰,我们只要着重看看这四个函数allocate deallocate construct destroy
申请一个空间遵循这 allocate一个内存空间(内部调用malloc函数)->
                   constuct在该空间构造一个对象(内部调用new(_ptr)valu_tpye(_Val) )->
                   destroy 析构对象(内部调用 _Ptr->~_Ty)
     deallocate 释放内存(内部调用free);

 template<class _Other>
  allocator<_Ty>& operator=(const allocator<_Other>&)
  { // assign from a related allocator (do nothing)
  return (*this);
  }
这个函数很有趣,当我们把一个allocator 赋值给另一个函数时,返回的是自身。也可以理解为什么都不做。如果要是真的把值赋过去了,可能会造成内存泄露。我觉得更好的做法是把operator=作为private,当你不小心调用时,编译器会明确提示你。

接着
  // allocator TEMPLATE OPERATORS
template<class _Ty,
 class _Other> inline
 bool operator==(const allocator<_Ty>&, const allocator<_Other>&)
 { // test for allocator equality (always true)
 return (true);
 }

template<class _Ty,
 class _Other> inline
 bool operator!=(const allocator<_Ty>&, const allocator<_Other>&)
 { // test for allocator inequality (always false)
 return (false);
 }
说明allocator是可以互换的,任何allocator都"相等"。

在接下去特例化了一个allocator<void>

template<> class _CRTIMP2 allocator<void>
{
 typedef void _Ty;
 typedef _Ty _FARQ *pointer;
 typedef const _Ty _FARQ *const_pointer;
 typedef _Ty value_type;
        ....
};
当  value_type _Ty 是void时 ,那么 sizof(void) , void &都是非法操作,所以特化一个,避免错误操作。

OK ,VS.NET 的 std::allocator大体上就是这样子了。vs的stl代码是 P.J.Plauger版本,Dinkumware公司编写。

可以发现,这个版本的allocator内存管理的核心只是简单封装了operator new 和 delete之类的基本操作,并没有什么神秘高明的地方。

2.SGI的allocator
  SGI 的allocator相关代码在stl_alloc.h中,代码相对复杂点。
  大体上有这么几个类
 
   template<int inst> class __malloc_alloc_template{...};   //一级配置器
   template<class _Alloc> class debug_alloc{...};           //for debug
   template <bool threads, int inst> class __default_alloc_template {...} //二级配置器
   template <class _Tp> class allocator {...}                             //标准 allocator
   template <class _Tp, class _Alloc>struct __allocator {...}             //转换接口
  
SGI默认的allocator是非标准的,但可以转换成标准的。它也提供标准的allocator。SGI allocator最大特色是提供了二级配置器,它在特定条件下启动,在分配小内存是更具效率和减少memory fragment。
  

3.定制allocator
有时候,为了追求更好的效率和性能,我门需要定制的allocator.现在我们已经对alloctor有了一定的了解了.那么改写一份特别的allocator也就不怎么困难了:

#ifndef _TEST_ALLOCATOR__
#define _TEST_ALLOCATOR__

class pool
{
public:
 template<class T>
 T* _allocate( ptrdiff_t size)
 {
  mem_+=size*sizeof(T);
  return (T*)mem_;
 }
 template<class T>
 void _deallocate( T*pointer, size_t n )
 {
  pointer-=n;
  mem_ = reinterpret_cast<char*>( pointer);
 }
 template<class T1,class T2>
 void _consturct( T1* p, const T2& val  )
 {
  new( p)T2( val);
 }

 template<class T>
 void _destroy( )
 {
  ;
 }
private:
  
 static char* mem_;
};

char buf[50000];
char* pool::mem_ = buf;

 

template <typename T> class pool_allocator;
template <> class pool_allocator<void>
{
public:
 typedef void* pointer;
 typedef const void* const_pointer;
 // reference to void members are impossible.
 typedef void value_type;
 template <class U>
 struct rebind { typedef pool_allocator<U> other; };
};   

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 {retuen &x;}
 const_pointer address(const_reference x) const {return &x;}
 pointer allocate(size_type size, pool_allocator<void>::const_pointer hint = 0)
 {
  return ( mem_pool._allocate<T>( (difference_type) size) );
 }
 //for Dinkumware:
 // char *_Charalloc(size_type n){return static_cast<char*>(mem_.allocate(n));}
 char* _Charalloc(size_type n)
 {
  return static_cast<char*> mem_::_allocate((difference_type)n,(pointer)0 );
 }
 // end Dinkumware

 template <class U> pool_allocator(const pool_allocator<U>&){}
 void deallocate(pointer p, size_type n)
 {
  mem_pool._deallocate( p,n);
 }
 void deallocate(void *p, size_type n)
 {
  //  mem_.deallocate(p, n);
  mem_pool._deallocate( (pointer)p,n );
 }
 size_type max_size() const throw() {return size_t(-1) / sizeof(value_type);}
 void construct(pointer p, const T& val)
 {
  mem_pool._consturct( p, val);
 }
 void construct(pointer p)
 {
  new(static_cast<void*>(p)) T();
 }
 void destroy( pointer p)
 {
  mem_pool._destroy<T>( );
 }

private:

    pool mem_pool;
};
//using lis sort need below
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

//test
 vector<int ,pool_allocator<int> > VI;
 VI.push_back(1);
 VI.push_back(2);
 cout<<VI[0]<<" "<<VI[1]<<endl;
 VI.pop_back();
 VI.pop_back();
 cout<<VI.size();
 
当然这是简单的不能最简单的mem pool,而且可能会造成问题。这里只是抛砖引玉,具体修改class pool即可。 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值