空间配置器allocator

来源:互联网 发布:喜欢用数据说话的女人 编辑:程序博客网 时间:2024/05/16 09:55

1、 什么是空间配置器

在我看来就是STL容器后面默默工作进行内存管理和分配以及回收的的一个组件,为什么不叫内存配置器?STL源码剖析里说到:

因为空间不一定是内存,空间也可以是磁盘或其他辅助的存储介质。

2、空间配置器的标准接口有哪些

  1. allocator::value_type
  2. allocator::pointor
  3. allocator::const_pointer
  4. allocator::reference
  5. allocator::const_reference
  6. allocator::size_type
  7. allocator::difference_type
  8. allocator::rebind 一个嵌套的class template
  9. allocator::allocator()
  10. allocator::allocator(allocator&)
  11. allocator::~allocator()
  12. template allocator::allocator(const allocator&)
  13. pointer allocator::address(reference x) const
  14. const_pointer allocator::address(const_reference x) const
  15. pointer allocator::allocate(size_type n, const void* = 0)
  16. void allocator::deallocate(pointer p, size_type n)
  17. size_type allocator::max_size() const
  18. void allocator::construct(pointer p, const T& x) == new((void*)p) T(x)
  19. void allocator::destroy(pointer p) == p->~T()

3、实现一个简单的空间配置器

#ifndef CALLOCATOR_H#define CALLOCATOR_H#include <new>#include <cstddef>#include <cstdlib>#include <climits>#include <iostream>template <class T>class CAllocator{    public:        typedef T value_type;        typedef T* pointer;        typedef const T* const_pointer;        typedef T& reference;        typedef const T& const_reference;        typedef size_t size_type;        typedef ptrdiff_t difference_type;        template <class U>        struct rebind        {            typedef CAllocator<U> other;        };        pointer allocate(size_type n, const void* hint = 0)        {            return (pointer)(::operator new(n * sizeof(T)));        }        void deallocate(pointer p, size_type n){ ::operator delete(p); }        void construct(pointer p, const T& x) { new(p) T(x);}        void destroy(pointer p) { p->~T(); }        pointer address(reference x) {return (pointer)&x; }        size_type max_size() const { return size_type(UINT_MAX / sizeof(T)); }        const_pointer const_address(const_pointer x){ return (const_pointer)&x; }        CAllocator(){};        ~CAllocator(){};    protected:    private:};#endif // CALLOCATOR_H
#include <iostream>#include "CAllocator.h"#include <vector>int main(){    int a[5] = {0,1,2,3,4};    std::vector<int, CAllocator<int> > av(a, a+5);    for(auto i: av)        std::cout << i << ' ';    std::cout << std::endl;    return 0;}

3、SGI STL的配置器与标准规范不同

SGI STL仍然提供了一个标准的配置接口,叫simple_alloc,而SGI STL的配置器叫alloc而非allocator,而且不接受任何参数,例如:

vector<int, std::allocator<int>> iv;vector<int, std::alloc> ic;

但是SGI STL里提供的配置器效率更加好!

4、一般C++的内存配置的操作和释放过程:

例如

class A{...};A* a = new A;delete a;

new的操作:
1. 调用::operator new 进行配置内存;
2. 调用A::A()进行构造;

delete的操作:
1. 调用A::~A()进行析构;
2. 调用::operator delete 进行内存释放;

而STL的空间配置器恰恰把这两阶段区分开来,
1. 内存的分配由alloc::allocate()负责
2. 内存的释放由alloc::deallocate()负责
3. 对象的构造由::construct()负责
4. 对象的析构由::destroy()负责

按照STL的标准

配置器应该定义于之中,而SGI内含两个文件

#include <stl_alloc.h> //负责内存的配置和释放#include <stl_construct.h>  //负责对象的构造和析构#include <stl_uninitialized.h> //定义了一些填充函数

#include <new.h>    //使用placement new template <class _T1, class _T2>inline void _Construct(_T1* __p, const _T2& __value) {  new ((void*) __p) _T1(__value);   //调用placement new;}template <class _T1>inline void _Construct(_T1* __p) {  new ((void*) __p) _T1();}template <class _Tp>inline void _Destroy(_Tp* __pointer) {  __pointer->~_Tp();  //调用对象的析构}//判断区间元素里是否有没有必要调用对象的析构函数template <class _ForwardIterator, class _Tp>inline void __destroy(_ForwardIterator __first, _ForwardIterator __last, _Tp*){  typedef typename __type_traits<_Tp>::has_trivial_destructor          _Trivial_destructor;  __destroy_aux(__first, __last, _Trivial_destructor());}//如果有必要就调用析构函数template <class _ForwardIterator>void__destroy_aux(_ForwardIterator __first, _ForwardIterator __last, __false_type){  for ( ; __first != __last; ++__first)    destroy(&*__first);}//没有必要就不调用析构函数,大大提升效率template <class _ForwardIterator> inline void __destroy_aux(_ForwardIterator, _ForwardIterator, __true_type) {}template <class _ForwardIterator>inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) {  __destroy(__first, __last, __VALUE_TYPE(__first));}template <class _T1, class _T2>inline void construct(_T1* __p, const _T2& __value) {  _Construct(__p, __value);}template <class _T1>inline void construct(_T1* __p) {  _Construct(__p);}template <class _Tp>inline void destroy(_Tp* __pointer) {  _Destroy(__pointer);}template <class _ForwardIterator>inline void destroy(_ForwardIterator __first, _ForwardIterator __last) {  _Destroy(__first, __last);}

空间的配置与释放

#ifdef __USE_MALLOC...typedef __malloc_alloc_template<0> malloc_alloc;typedef malloc_alloc alloc; //第一级配置器...#else...typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;//第二级配置器#endif

为了使SGI配置器符合STL规格,又进行一次简单的封装:

template<class T, class Alloc>class simple_alloc{    public:    static T* allocate(size_t n)    {        return 0 == n ? 0 : (T*)Alloc::allocate(n * sizeof(T));    }    static T* allocate(void)    {        return (T*)Alloc::allocate(sizeof(T));    }    static void deallocate(T *p, size_t n)    {        if(n != 0)            Alloc::deallocate(p, n * sizeof(T));    }    static coid deallocate(T *p)    {        Alloc::deallocate(p, sizeof(T));    }}

如何使用这个接口:

template <class T, class Alloc = alloc>class vector {    protected:    typedef simple_alloc<value_type, Alloc> data_allocator;    ...}

SGI STL 第一级配置器

template<int inst>class __malloc_alloc_template{...};

其中:
1. allocate()直接使用malloc();
2. deallocate()直接使用free();
3. 模拟C++中的set_new_handler()以处理内存不足的情况

SGI STL 第二级配置器

template <bool threads, int inst>class __default_alloc_template{...};

其中:
1. 维护16个自由链表,负责16种小型区块的次配置能力,内存池以malloc()配置而得。如果内存不足,转调用第一级配置器。
2. 如果需求区块大于128bytes,就调用第一级配置器

0 0
原创粉丝点击