C++: STL内存分配器--allocator

STL内存分配器--allocator

  • 一、STL内存分配器
  • 二、STL allocator


一、STL内存分配器

分配器(allocator))是C ++标准库的一个组件, 主要用来处理所有给定容器(vector,list,map等)内存的分配和释放。C ++标准库提供了默认使用的通用分配器std::allocator,但开发者可以自定义分配器。
GNU STL除了提供默认分配器,还提供了__pool_alloc、__mt_alloc、array_allocator、malloc_allocator 内存分配器。
__pool_alloc :SGI内存池分配器
__mt_alloc : 多线程内存池分配器
array_allocator : 全局内存分配,只分配不释放,交给系统来释放
malloc_allocator :堆std::malloc和std::free进行的封装

二、STL allocator

1、STL allocator简介
new会分配内存并执行对象构造函数,delete会执行对象析构函数并释放内存。如果将内存分配和对象构造分离,可以先分配大块内存,只在需要时才真正执行对象构造函数。
STL在头文件memory中提供了一个allocator类,允许将分配和对象构造分离,提供更好的性能和更灵活的内存管理能力。为了定义一个allocator对象,必须指明allocator可以分配的对象类型。当allocator分配内存时,会根据给定的对象类型来确定恰当的内存大小和对齐位置。

  template<typename _Tp>
    class allocator : public __allocator_base<_Tp>
    {
   public:
      typedef size_t     size_type;
      typedef ptrdiff_t  difference_type;
      typedef _Tp*       pointer;
      typedef const _Tp* const_pointer;
      typedef _Tp&       reference;
      typedef const _Tp& const_reference;
      typedef _Tp        value_type;

      template<typename _Tp1>
	struct rebind
	{ typedef allocator<_Tp1> other; };


      allocator() throw() { }

      allocator(const allocator& __a) throw()
      : __allocator_base<_Tp>(__a) { }

      template<typename _Tp1>
	allocator(const allocator<_Tp1>&) throw() { }

      ~allocator() throw() { }

      // Inherit everything else.
    };

根据C++标准规范,STL中分配器的对外接口、成员变量都一样,只是接口内部实现有区别。
allocator实现在模板类new_allocator中:

  template<typename _Tp>
    class new_allocator
    {
    public:
      typedef size_t     size_type;
      typedef ptrdiff_t  difference_type;
      typedef _Tp*       pointer;
      typedef const _Tp* const_pointer;
      typedef _Tp&       reference;
      typedef const _Tp& const_reference;
      typedef _Tp        value_type;

      template<typename _Tp1>
	struct rebind
	{ typedef new_allocator<_Tp1> other; };

      new_allocator() _GLIBCXX_USE_NOEXCEPT { }

      new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { }

      template<typename _Tp1>
	  new_allocator(const new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { }

      ~new_allocator() _GLIBCXX_USE_NOEXCEPT { }

      pointer
      address(reference __x) const _GLIBCXX_NOEXCEPT
      { return std::__addressof(__x); }

      const_pointer
      address(const_reference __x) const _GLIBCXX_NOEXCEPT
      { return std::__addressof(__x); }

      // NB: __n is permitted to be 0.  The C++ standard says nothing
      // about what the return value is when __n == 0.
      pointer
      allocate(size_type __n, const void* = static_cast<const void*>(0))
      {
		if (__n > this->max_size())
		  std::__throw_bad_alloc();
		return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
      }

      // __p is not permitted to be a null pointer.
      void
      deallocate(pointer __p, size_type)
      {
      	::operator delete(__p);
      }

      size_type
      max_size() const _GLIBCXX_USE_NOEXCEPT
      { return size_t(-1) / sizeof(_Tp); }

#if __cplusplus >= 201103L
      template<typename _Up, typename... _Args>
	void
	construct(_Up* __p, _Args&&... __args)
	{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }

      template<typename _Up>
	void
	destroy(_Up* __p) { __p->~_Up(); }
#else
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_] allocator::construct
      void
      construct(pointer __p, const _Tp& __val)
      { ::new((void *)__p) _Tp(__val); }

      void
      destroy(pointer __p) { __p->~_Tp(); }
#endif
    };

  template<typename _Tp>
    inline bool
    operator==(const new_allocator<_Tp>&, const new_allocator<_Tp>&)
    { return true; }

  template<typename _Tp>
    inline bool
    operator!=(const new_allocator<_Tp>&, const new_allocator<_Tp>&)
    { return false; }

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

STL中容器默认分配器为std::allocator<_Tp>,内存分配和释放的接口allocate和deallocate内部实现只是将::operator new和::operator delete进行封装,没用做特殊处理。

3、STL allocator实例

4、自定义allocator
实现Allocator只需要实现allocate和deallocate,来实现自己的内存分配策略。

template<class T >
inline T*_allocate(ptrdiff_t num,T*){
    std::cout<<"_allocate"<<endl;
    return static_cast<T*>(::operator new(num*sizeof(T)));
}
template <class T>
inline void _deallocate(T* buff){
    std::cout<<"_deallocate"<<endl;
    ::operator delete(buff);
}

template <class T ,class U>
inline void _construct(T* p,const U& value){
    new(p)T(value);
}
template<class T>
inline void _destory(T* p){
    p->~T();
}
template<typename T>
class MyAlloctor{
    public:
        typedef T        value_type;
        typedef T*       pointer;
        typedef T&       reference;
        typedef const T* const_pointer;
        typedef const T& const_reference;
        typedef size_t     size_type;
        typedef ptrdiff_t  difference_type;
        template<typename _Tp1>struct rebind{ typedef MyAlloctor<_Tp1> other; };

    MyAlloctor()=default;
    ~MyAlloctor()=default;
    pointer address(reference x){
        return static_cast<pointer>(&x);
    }
    const_pointer address(const_reference x){
        return static_cast<const_pointer>(&x);
    }

    pointer allocate(size_type _n,const void* hit=0 ){
        return _allocate(_n,(pointer)0);
    }

    void deallocate(pointer p,size_type _n){
        _deallocate(p);
    }

    size_type max_size()const throw(){
        return static_cast<size_type>(INT_MAX/sizeof(T));
    }

    void construct(pointer p,const_reference value){
        _construct(p,value);
    }

    void destroy(pointer p){
        _destory(p);
    }

};

测试代码:

#include 
#include 
#include 
#include 
using namespace std;
using namespace __gnu_cxx;//引入new_allocator
class base
{
    string name;
    int value;
public:
    base():name("test"),value(0) { cout << "base ctor" << endl; }
    explicit base(int v):name("explicit name"),value(v){cout<<"base ctor value="<<value<<endl;}
    virtual ~base() { cout << "base dtor" << endl; }
    base(const base& value) { cout << "Copy ctor" << endl; }
    base(base&& value) { cout << "move ctor" << endl; }
    void who(void){cout<<name<<" value= "<<value<<endl;}
};

int main(void){

new_allocator<base>alloc_test;
new_allocator<base>test;
base* p = alloc_test.allocate(3);

cout<<"test1 start"<<endl;
cout<<"size of base="<<sizeof(base)<<endl;
cout<<"size of *p="<<sizeof(*p)<<endl;
p->who();
//(p+1)->who();
cout<<"test1 end\n"<<endl;
cout<<"test2 start"<<endl;
//test.construct(p,base(1));
//test.construct(p+1,base(2));
//test.construct(p+2,base(3));

alloc_test.construct(p,base(1));
alloc_test.construct(p+1,base(2));
alloc_test.construct(p+2,base(3));


p->who();
(p+1)->who();
(*p).who();
alloc_test.deallocate(p, 3);
getchar();
}
-----------------------------------
// output:
//todo
base dtor  //析构对象(仍然占有空间)
test deallocate//删除指针,释放空间。

你可能感兴趣的:(cxx,c++,开发语言)