空间配置器allocator

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值