STL之空间配置器源码解析

配置器(allocator)

配置器:负责空间配置与管理,从实现的角度来看,配置器是一个实现了动态空间配置、空间管理、空间释放的模板类。

空间配置器意义:整个 STL 的操作对象(包含的所有数值)都存放在容器之内,空间配置器就是用来帮助这些容器管理(动态开辟,回收)内存空间,使其可以动态存放内容。

SGI STL 空间配置器的文件结构

SGI STL 的配置器,其名称是 alloc 而不是 allocator,而且不接受任何参数。SGI 也定义有allocator配置器,但是因为效率不佳,SGI 并未使用,也不建议我们使用,它只是基层内存配置/释放行为(::operator::new 和 ::operator::delete)的一层薄薄的包装。被定义在 defalloc.h文件中。

SGI STL 的每一个容器都已经指定其缺省(默认)的空间配置器为 alloc,例如:vector 。

template <class T, class Alloc = alloc>  // 默认使用 alloc 为配置器
class vector {...};

vector<int, std::alloc> iv; 

空间配置器相关头文件:
在这里插入图片描述

  • <stl_construct.h>:定义了全局函数 construct() 和 destroy(),负责对象的构造和析构
  • <stl_alloc.h>:定义了一、二级配置器,配置器名为 alloc, 处理对象构造前的空间配置 和 对象析构后的空间释放
  • <stl_uninitialized.h>:定义了全局函数,用来填充(fill)或复制(copy)大块内存数据。
  • <defalloc.h>:SGI 标准的空间配置器,std::allocator
  • <README.md> :是一些描述信息;(本篇文章中包含这些信息)

空间配置器的文件分析:

defalloc.h 只是为了兼容,SGI并不使用,那么我们如何处理配置器的new和delete操作呢?
已知一个对象的创建和销毁如下:

 class TestA
 {...}
 TestA* test = new TestA; //1.分配对象内存空间 2.调用构造函数初始化对象
 delete test;  //1.调用对象析构函数 2.释放对象占用内存空间

结论:

new 的操作中需要完成两件事:(1,2就是先后顺序)

  • 1.分配对象内存空间 (stl_alloc.h文件中)alloc::allocate()处理
  • 2.调用构造函数初始化对象 (stl_construct.h文件中) construct()处理

delete 的操作中需要完成两件事:(1,2就是先后顺序)

  • 1.调用对象析构函数 (stl_alloc.h文件中)alloc::deallocate()处理
  • 2.释放对象占用的内存空间 (stl_construct.h文件中) destroy()处理

所以new 和 delete 的操作全部在 “stl_alloc.h” 和 “stl_construct.h” 文件中完成了。
以上就是各自文件需要处理的基本工作内容;

需要思考的问题:

  • 如何向堆内存请求空间
  • 多线程环境下如何请求空间
  • 内存不足时需要如何处理
  • 请求过多 “小型区块” 空间,可能造成的内存碎片问题如何处理

SGI STL 空间配置器

STL 采用两级配置器:

  • 第一级配置器直接使用 malloc() 和 free() 实现;
  • 第二级配置器使用 memory pool 内存池管理(用来解决,小型区块可能造成内存碎片的问题)

分配规则:

  • 当请求空间大小 > 128 bytes,使用第一级配置器(malloc() 和 free())
  • 当请求空间大小 <= 128 bytes,使用第二级配置器(内存池管理)
    (具体原理我们根据源代码具体分析)

源码分析

1.“stl_alloc.h”

第一级配置器 ( 使用 malloc() 和 free() 实现,比较简单 )

// 第一级配置器
// 该泛型类没有类型参数;
//“__inst”是一个写死的int类型,但无实际意义
template <int __inst>
class __malloc_alloc_template {

private:
  	//以下两个函数是,malloc 申请失败后(内存不足时)的处理方法
	//用来申请空间,参数是申请的大小
  static void* _S_oom_malloc(size_t);  
  //用来扩增一个旧的内存空间
  //参数1,是旧的空间地址;参数2,是重新申请的大小
  static void* _S_oom_realloc(void*, size_t);

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
  //这是一个函数指针(指向函数的指针)
  static void (* __malloc_alloc_oom_handler)();
#endif

public:

	//请求分配空间
  static void* allocate(size_t __n)
  {
	  // 调用 malloc()
    void* __result = malloc(__n);
    // 如果申请失败,改用 _S_oom_malloc()
    if (0 == __result) __result = _S_oom_malloc(__n);
    return __result;
  }

  //释放空间,参数1,地址指针;参数2,大小
  //(很显然这里的第二参数没有意义)
  // 调用 free()释放空间
  static void deallocate(void* __p, size_t /* __n */)
  {
    free(__p);
	//(为何__n 没有意义,c语言得知,free释放空间,是全部释放,不存在只释放一部分的情况)
  }
  
  //对一段旧空间扩容
  static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz)
  {
	  // 调用 realloc()
    void* __result = realloc(__p, __new_sz);
	// 如果申请失败,改用 _S_oom_malloc()
    if (0 == __result) __result = _S_oom_realloc(__p, __new_sz);
    return __result;
  }

  //动态指定,针对内存不足时的处理方法(注意书写格式)
  static void (* __set_malloc_handler(void (*__f)()))()
  {
    void (* __old)() = __malloc_alloc_oom_handler;
    __malloc_alloc_oom_handler = __f;
    return(__old);
  }
};

// malloc_alloc 针对内存不足时的处理方法
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
// 默认为0
template <int __inst>
void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0;
#endif

template <int __inst>
void*
__malloc_alloc_template<__inst>::_S_oom_malloc(size_t __n)
{
    void (* __my_malloc_handler)(); //声明一个处理内存不足的函数指针;
    void* __result;  

    // 一直申请直到失败或成功
    for (;;) {
        __my_malloc_handler = __malloc_alloc_oom_handler;
		//当 "内存不足处理方法" 并未被设置,便调用 __THROW_BAD_ALLOC,抛出异常信息
        if (0 == __my_malloc_handler) { __THROW_BAD_ALLOC; }
		// 调用内存不足时的处理函数
        (*__my_malloc_handler)();  
        __result = malloc(__n);   // 再次尝试申请内存
        if (__result) return(__result);
    }
}

//  给一个已经分配了地址的指针重新分配空间
template <int __inst>
void* __malloc_alloc_template<__inst>::_S_oom_realloc(void* __p, size_t __n)
{
    void (* __my_malloc_handler)();
    void* __result;
    for (;;) {
        __my_malloc_handler = __malloc_alloc_oom_handler;
        if (0 == __my_malloc_handler) { __THROW_BAD_ALLOC; }
        (*__my_malloc_handler)();   
        __result = realloc(__p, __n);  
        if (__result) return(__result);
    }
}

simple_alloc:

//第二层包装,(一个简单的调用配置器的模板类)
//_Alloc可以选择调用的空间配置器(第一级或第二级)
//_Tp需要申请的对象的类型
template<class _Tp, class _Alloc>
class simple_alloc {

public:
    // 申请n个_Tp类型的对象空间
    static _Tp* allocate(size_t __n)
      { return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof (_Tp)); }
	//申请一个_Tp类型的对象空间
    static _Tp* allocate(void)
      { return (_Tp*) _Alloc::allocate(sizeof (_Tp)); }
	//释放_p的对象空间,
	//(对于第一级配置器来讲__n没有实际意义)
    static void deallocate(_Tp* __p, size_t __n)
      { if (0 != __n) _Alloc::deallocate(__p, __n * sizeof (_Tp)); }
    static void deallocate(_Tp* __p)
      { _Alloc::deallocate(__p, sizeof (_Tp)); }
};

debug_alloc ,检测存储的数据是否被改变;

// Allocator adaptor to check size arguments for debugging.
// Reports errors using assert.  Checking can be disabled with
// NDEBUG, but it's far better to just use the underlying allocator
// instead when no checking is desired.
// There is some evidence that this can confuse Purify.

// 把申请的内存空间首地址内容用于存放n的大小, 方便后面校验是否偏移 
// 主要用于保护存储的数据不被随意改变
template <class _Alloc>
class debug_alloc {

private:
	// _S_extra 的存在会导致,不会分配大小为0的内存空间
  enum {_S_extra = 8};  // Size of space used to store size.  Note
                        // that this must be large enough to preserve
                        // alignment.

public:
 
	//多开辟了 _S_extra 大小的空间,用来存放申请的大小
  static void* allocate(size_t __n)
  {
    char* __result = (char*)_Alloc::allocate(__n + (int) _S_extra);
    *(size_t*)__result = __n; //首地址用来存放__n的大小
    return __result + (int) _S_extra; //返回指向存放数据的起始地址
  }

  static void deallocate(void* __p, size_t __n)
  {
    char* __real_p = (char*)__p - (int) _S_extra;
	// 检查是否发生偏移
    assert(*(size_t*)__real_p == __n);
    _Alloc::deallocate(__real_p, __n + (int) _S_extra);
  }

  static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz)
  {
    char* __real_p = (char*)__p - (int) _S_extra;
    assert(*(size_t*)__real_p == __old_sz);
    char* __result = (char*)
      _Alloc::reallocate(__real_p, __old_sz + (int) _S_extra,
                                   __new_sz + (int) _S_extra);
    *(size_t*)__result = __new_sz;
    return __result + (int) _S_extra;
  }
};

第二级配置器 ( 内存池管理 )

相对于第一级配置器,多了一些操作机制,其作用主要是避免太多小额区块造成内存的碎片。
其实小额区块带来的不仅是内存碎片,配置空间时的额外负担也是一个大问题,虽然额外负担永远无法避免,但是小额区块越小,额外负担所占的比例就越大,显得更加浪费。

分配规则:当请求空间大小 > 128 bytes,转到第一级配置器,否则就使用 _S_free_list 中的空间。

关键结构信息如下:

enum {_ALIGN = 8};  // 小型区块上调边界,即区块大小的增长倍数
enum {_MAX_BYTES = 128}; // 小区块的存储上限
enum {_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN  free-list 的个数

// free-list 的 node 节点结构,注意,这是一个联合体对象
union _Obj {
    union _Obj* _M_free_list_link;  // 利用联合体特点
    char _M_client_data[1];   
};
// 这是一个存放了16个 *_Obj 对象 的数组
 //  __STL_VOLATILE 是 “volatile”
static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS]; 

其中 free-list 是指针数组(存放指针的数组),16 个数组元素,各自管理大小分别为 8, 16, 24, 32,…128 bytes(8 的倍数)的小额区块。

内存池节点信息:

  static char* _S_start_free;  // 内存池起始位置。只在 _S_chunk_alloc() 中变化
  static char* _S_end_free;    // 内存池结束位置。只在 _S_chunk_alloc() 中变化
  static size_t _S_heap_size;  // 在堆内存中已经申请的内存大小(累计大小)

如图空闲链表和内存池:
在这里插入图片描述
申请空间简单分析典型的三种情况,具体在源码中分析:
在这里插入图片描述
在这里插入图片描述

源码:

//没有模板类型参数
//参数1,用于多线程;参数2,无意义
template <bool threads, int inst>
class __default_alloc_template {

private:
  // Really we should use static const int x = N
  // instead of enum { x = N }, but few compilers accept the former.
	//这里如果使用 static const 去替代 enum ,设置数值大小更好
#if ! (defined(__SUNPRO_CC) || defined(__GNUC__))
    enum {_ALIGN = 8};  // 小型区块的上调边界
    enum {_MAX_BYTES = 128}; // 小区区块的上限
    enum {_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN  free-list 的个数
# endif 
	// 向上舍入操作 ,这个计算方法可以学习一下
  // 将请求的小额区块的大小调至 8 的倍数
  static size_t
  _S_round_up(size_t __bytes) 
    { return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); }

__PRIVATE:

   // 注意:这里使用一个union,做了简单的内存优化
   // 1.如果使用第一个成员, 表示指向另一个相同的 union 对象
   // 2.如果使用第二个成员, 表示指向实际的内存区域  
   // 如此一来,一个结点使用相同的空间, 却能同时做两件事,索引和指向内存区域
   //为什么要这样做呢?因为节点在使用和空闲时是两个状态,
   // 使用时需要存放数据;空闲时需要将相同大小的内存块节点链接起来

  // free-list 的节点结构,降低维护链表 list 带来的额外负担
  union _Obj {
        union _Obj* _M_free_list_link;  // 利用联合体特点
        char _M_client_data[1];    /* The client sees this. */
  };
private:
# if defined(__SUNPRO_CC) || defined(__GNUC__) || defined(__HP_aCC)
    static _Obj* __STL_VOLATILE _S_free_list[]; 
        // Specifying a size results in duplicate def for 4.1
# else
	// 这是一个空闲列表,会将所有当前空闲(回收)的内存暂时保存起来,
	// 数组元素中存放空闲区块链表
	//使用前会全部初始化为0
    static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS];  
# endif 
  //根据数据大小找到对应 _S_free_list 的下标,下标从 0 开始
  static  size_t _S_freelist_index(size_t __bytes) {
        return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1);
  }

  // Returns an object of size __n, and optionally adds to size __n free list.
  //当_S_free_list 对应下标的没有多余的空闲区块时调用
  //向内存池申请 __n 个大小的空间,默认会要20个,但是真的给多少个内存池说了算
  static void* _S_refill(size_t __n);
  // Allocates a chunk for nobjs of size size.  nobjs may be reduced
  // if it is inconvenient to allocate the requested number.
  //内存池分配空间
  //参数1,申请__size 大小的空间
  //参数2,参数1大小的空间 __nobjs 个
  static char* _S_chunk_alloc(size_t __size, int& __nobjs);

  // Chunk allocation state.
  static char* _S_start_free;  // 内存池起始位置。只在 _S_chunk_alloc() 中变化
  static char* _S_end_free;    // 内存池结束位置。只在 _S_chunk_alloc() 中变化
  static size_t _S_heap_size;  // 在堆内存中已经申请的内存大小

# ifdef __STL_THREADS
    static _STL_mutex_lock _S_node_allocator_lock;
# endif

    // It would be nice to use _STL_auto_lock here.  But we
    // don't need the NULL check.  And we do need a test whether
    // threads have actually been started.
	//这里最好使用_STL_auto_lock。但我们不需要NULL检查。
	//我们需要检测一下线程是否已经启动。
    class _Lock;
    friend class _Lock;
    class _Lock {
        public:
            _Lock() { __NODE_ALLOCATOR_LOCK; }
            ~_Lock() { __NODE_ALLOCATOR_UNLOCK; }
    };

public:

  // 申请大小为n的数据块,返回该数据块的起始地址 
  static void* allocate(size_t __n)
  {
    void* __ret = 0;

    // 申请的内存大小大于 128 就去第一空间配置器中申请内存
    if (__n > (size_t) _MAX_BYTES) {
      __ret = malloc_alloc::allocate(__n);
    }
    else {
      //根据申请的空间大小获取对应的数组下标,得到我们将要获取的空闲区块链表首地址
	 //这里要注意,比如我们申请的是 7,但是不会真的给7,而是会给8,
	 //那么就意味着每次分配内存,只会多给,不会少给,
	 //所以在扩容的时候,可能从7扩容到8,但是实际处理不会再次给你分配内存,会直接给你返回
      _Obj* __STL_VOLATILE* __my_free_list
          = _S_free_list + _S_freelist_index(__n);
      // Acquire the lock here with a constructor call.
      // This ensures that it is released in exit or during stack
      // unwinding.
#     ifndef _NOTHREADS
      /*REFERENCED*/
      _Lock __lock_instance;
#     endif
	  //获取得到这个申请的空间对象
      _Obj* __RESTRICT __result = *__my_free_list;
	  //__result == 0 说明没有内存块,首先将申请的大小调至 8 的倍数
	  //然后填充内存
      if (__result == 0)
        __ret = _S_refill(_S_round_up(__n));
      else {
        // 如果空闲链表中有空闲数据块,则取出一个,并把空闲链表的指针指向下一个空闲数据块  
        *__my_free_list = __result -> _M_free_list_link;
        __ret = __result;
      }
    }

    return __ret;
  };


  //回收函数
  static void deallocate(void* __p, size_t __n)
  {
    if (__n > (size_t) _MAX_BYTES)  
		// 大于 128,调用第一级配置器的释放
      malloc_alloc::deallocate(__p, __n);   
    else {
		// 获取当前空闲列表中对应 __n 大小对应下标中存储的“空闲区块链表”头节点
      _Obj* __STL_VOLATILE*  __my_free_list
          = _S_free_list + _S_freelist_index(__n);     
      _Obj* __q = (_Obj*)__p;

      // acquire lock
#       ifndef _NOTHREADS
      /*REFERENCED*/
      _Lock __lock_instance;
#       endif /* _NOTHREADS */
	  //头插回收数据块,将“空闲区块链表”头指针前移,并存入空闲数组中
      __q -> _M_free_list_link = *__my_free_list;  
      *__my_free_list = __q;
      // lock is released here
    }
  }

  //扩容
  static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz);

} ;

//重命名
typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc; 
typedef __default_alloc_template<false, 0> single_client_alloc;

template <bool __threads, int __inst>
inline bool operator==(const __default_alloc_template<__threads, __inst>&,
                       const __default_alloc_template<__threads, __inst>&)
{
  return true;
}

# ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDER
template <bool __threads, int __inst>
inline bool operator!=(const __default_alloc_template<__threads, __inst>&,
                       const __default_alloc_template<__threads, __inst>&)
{
  return false;
}
# endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER */

/* We allocate memory in large chunks in order to avoid fragmenting     */
/* the malloc heap too much.                                            */
/* We assume that size is properly aligned.                             */
/* We hold the allocation lock.                                         */
// 从内存池中申请空间
// 参数1,申请 __size 大小的空间内存
// 参数2,参数1那么大的空间内存,索要__nobjs个,但是具体给多少,还要看内存池,所以这是一个引用
template <bool __threads, int __inst>
char*
__default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size, 
                                                            int& __nobjs)
{
    char* __result;
    size_t __total_bytes = __size * __nobjs;  // 想要申请空间的总大小
    size_t __bytes_left = _S_end_free - _S_start_free;  // 计算内存池剩余空间
	// 内存池剩余空间充足,全部给
    if (__bytes_left >= __total_bytes) {  
        __result = _S_start_free;   //返回这块空间首地址
        _S_start_free += __total_bytes;  //剩余空间的首地址指针需要偏移
        return(__result);
    } else if (__bytes_left >= __size) {  // 内存池剩余空间不足提供__nobjs个,能给多少给多少
        __nobjs = (int)(__bytes_left/__size);
        __total_bytes = __size * __nobjs;
        __result = _S_start_free;
        _S_start_free += __total_bytes;
        return(__result);
    } else {      // 内存池剩余空间连一个都给不了  
    	//扩容内存池,申请的新大小                                           
        size_t __bytes_to_get = 
	  2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
        // Try to make use of the left-over piece.
	    // 内存池的剩余空间,全部分给对应下标的空闲区块链表
        if (__bytes_left > 0) {
            _Obj* __STL_VOLATILE* __my_free_list =
                        _S_free_list + _S_freelist_index(__bytes_left);

            ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list;
            *__my_free_list = (_Obj*)_S_start_free;
        }
		//调用malloc,扩容内存池
        _S_start_free = (char*)malloc(__bytes_to_get);  
        if (0 == _S_start_free) {  // 内存申请失败,堆内存空间不足
            size_t __i;
            _Obj* __STL_VOLATILE* __my_free_list;
			_Obj* __p;
            // Try to make do with what we have.  That can't
            // hurt.  We do not try smaller requests, since that tends
            // to result in disaster on multi-process machines.
			//如果失败了,就去大于 __size 的空闲区块空间索取
            for (__i = __size;
                 __i <= (size_t) _MAX_BYTES;
                 __i += (size_t) _ALIGN) {
                __my_free_list = _S_free_list + _S_freelist_index(__i);
                __p = *__my_free_list;
                if (0 != __p) {
					//将空闲区块链表的首数据块回收,并将该空闲区块首地址偏移到下一位
                    *__my_free_list = __p -> _M_free_list_link;
                    _S_start_free = (char*)__p;
                    _S_end_free = _S_start_free + __i;
					//然后重新去内存池分配并返回
                    return(_S_chunk_alloc(__size, __nobjs));
                    // Any leftover piece will eventually make it to the
                    // right free list.
                }
            }
		//走到这里说明,去空闲链表回收也失败了,就调用第一级配置器
	    _S_end_free = 0;	// In case of exception.
        _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);  
            // This should either throw an
            // exception or remedy the situation.  Thus we assume it
            // succeeded.
        }
		//扩容内存池成功后,继续申请空间
        _S_heap_size += __bytes_to_get;
        _S_end_free = _S_start_free + __bytes_to_get;
        return(_S_chunk_alloc(__size, __nobjs));  
    }
}


/* Returns an object of size __n, and optionally adds to size __n free list.*/
/* We assume that __n is properly aligned.                                */
/* We hold the allocation lock.                                         */

//向内存池申请空闲空间,返回一个大小为__n的对象,
//如果申请较多区块,那么会为 _S_free_list 对应下标的空闲区块链表,新增节点
template <bool __threads, int __inst>
void*
__default_alloc_template<__threads, __inst>::_S_refill(size_t __n)
{
    int __nobjs = 20;
    // 调用 _S_chunk_alloc(),默认申请 20 个 __n 大小的区块
    char* __chunk = _S_chunk_alloc(__n, __nobjs);
    _Obj* __STL_VOLATILE* __my_free_list;
    _Obj* __result;      //客户端申请的对象结果
    _Obj* __current_obj;  //当前空闲对象
    _Obj* __next_obj;   //下一个空闲对象
    int __i;

    // 如果只获得一个数据块,那么直接返回
    if (1 == __nobjs) return(__chunk);
	// 超过1 ,需要将多余的加入到空闲列表中
	// 根据申请数据块的大小找到数组下标,并定位了该数组元素(空闲区块链表头节点)
    __my_free_list = _S_free_list + _S_freelist_index(__n);   

    /* Build free list in chunk */
      __result = (_Obj*)__chunk;
	  // 这是一个连续的空间,所以将前 __n 返回给用户,
	  // 然后开始将后面的内存按照 __n的大小进行拆分成 (__nobjs - 1)个空闲区块节点并链接起来
      *__my_free_list = __next_obj = (_Obj*)(__chunk + __n); 
      for (__i = 1; ; __i++) {
        __current_obj = __next_obj;
        __next_obj = (_Obj*)((char*)__next_obj + __n);
        if (__nobjs - 1 == __i) {
            __current_obj -> _M_free_list_link = 0;
            break;
        } else {
            __current_obj -> _M_free_list_link = __next_obj;
        }
      }
    return(__result);
}

//扩容
template <bool threads, int inst>
void*
__default_alloc_template<threads, inst>::reallocate(void* __p,
                                                    size_t __old_sz,
                                                    size_t __new_sz)
{
    void* __result;
    size_t __copy_sz;

	//新旧大小都大于 128 那么直接调用第一配置器扩容
    if (__old_sz > (size_t) _MAX_BYTES && __new_sz > (size_t) _MAX_BYTES) {
        return(realloc(__p, __new_sz));
    }
	//如果新旧大小所在的区块最大容量相同,那么直接返回
    if (_S_round_up(__old_sz) == _S_round_up(__new_sz)) return(__p);
	//先申请一块新的空间
    __result = allocate(__new_sz);
    __copy_sz = __new_sz > __old_sz? __old_sz : __new_sz;
	//将旧数据从旧空间复制到新空间
    memcpy(__result, __p, __copy_sz);
	//将旧的区块空间回收
    deallocate(__p, __old_sz);
    return(__result);
}

#ifdef __STL_THREADS
    template <bool __threads, int __inst>
    _STL_mutex_lock
    __default_alloc_template<__threads, __inst>::_S_node_allocator_lock
        __STL_MUTEX_INITIALIZER;
#endif

// 静态成员变量的定义与初值设定
template <bool __threads, int __inst>
char* __default_alloc_template<__threads, __inst>::_S_start_free = 0;

template <bool __threads, int __inst>
char* __default_alloc_template<__threads, __inst>::_S_end_free = 0;

template <bool __threads, int __inst>
size_t __default_alloc_template<__threads, __inst>::_S_heap_size = 0;

template <bool __threads, int __inst>
typename __default_alloc_template<__threads, __inst>::_Obj* __STL_VOLATILE
__default_alloc_template<__threads, __inst> ::_S_free_list[
# if defined(__SUNPRO_CC) || defined(__GNUC__) || defined(__HP_aCC)
    _NFREELISTS
# else
    __default_alloc_template<__threads, __inst>::_NFREELISTS
# endif
] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
// The 16 zeros are necessary to make version 4.1 of the SunPro
// compiler happy.  Otherwise it appears to allocate too little
// space for the array.

#endif /* ! __USE_MALLOC */
2.“stl_construct.h”

调用对象的构造函数和析构函数:

#ifndef __SGI_STL_INTERNAL_CONSTRUCT_H
#define __SGI_STL_INTERNAL_CONSTRUCT_H

#include <new.h>  // 使用 placement new,需要先包含此文件。

__STL_BEGIN_NAMESPACE

// construct and destroy.  These functions are not part of the C++ standard,
// and are provided for backward compatibility with the HP STL.  We also
// provide internal names _Construct and _Destroy that can be used within
// the library, so that standard-conforming pieces don't have to rely on
// non-standard extensions.

// Internal names

// 将初值 __value 设定到指针所指的空间上。
template <class _T1, class _T2>
inline void _Construct(_T1* __p, const _T2& __value) {
  new ((void*) __p) _T1(__value);   // placement new,调用 _T1::_T1(__value);
}

template <class _T1>
inline void _Construct(_T1* __p) {
  new ((void*) __p) _T1();
}

// 对象指针调用对象的析构函数
template <class _Tp>
inline void _Destroy(_Tp* __pointer) {
  __pointer->~_Tp();
}

// __first 和 __last 是两个迭代器
// 第三个参数如果是 __false_type,
// 以循环的方式遍历整个范围,并在循环中每经历一个对象就调用 destory()。
// non-trivial_destructor
template <class _ForwardIterator>
void
__destroy_aux(_ForwardIterator __first, _ForwardIterator __last, __false_type)
{
  for ( ; __first != __last; ++__first)
    destroy(&*__first);
}

// 第三个参数如果是 __true_type,什么都不做;
// trivial_destructor
template <class _ForwardIterator> 
inline void __destroy_aux(_ForwardIterator, _ForwardIterator, __true_type) {}

//分析1:为什么用 __false_type 和 __true_type 区分调用 __destroy_aux() 函数
//在两个迭代器中一直调用 destroy 去销毁,如果很多都是一些无关痛痒的析构函数(trivial_destructor),
//那么这样循环调用析构函数,对效率来讲也是一种伤害。

//分析2:trivial_destructor和non-trivial_destructor的区别:
//如果用户不定义析构函数,而一直使用默认的析构函数,我们称之为 trivial_destructor
//如果用户定义了析构函数,在析构函数中做了一些事情,我们称之为 non-trivial_destructor

// 利用 _Trivial_destructor 判断调用哪个 __destroy_aux() 函数
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());
}

// 调用 __VALUE_TYPE() 获得迭代器所指对象的类型。
template <class _ForwardIterator>
inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) {
  __destroy(__first, __last, __VALUE_TYPE(__first));
}

// destroy 泛型特化
inline void _Destroy(char*, char*) {}
inline void _Destroy(int*, int*) {}
inline void _Destroy(long*, long*) {}
inline void _Destroy(float*, float*) {}
inline void _Destroy(double*, double*) {}
#ifdef __STL_HAS_WCHAR_T
inline void _Destroy(wchar_t*, wchar_t*) {}
#endif /* __STL_HAS_WCHAR_T */

// --------------------------------------------------
// Old names from the HP STL.

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);
}

//  __first 和 __last 是两个迭代器,函数的意义是将 [__first, __last)范围内的所有对象析构掉。
template <class _ForwardIterator>
inline void destroy(_ForwardIterator __first, _ForwardIterator __last) {
  _Destroy(__first, __last);
}

__STL_END_NAMESPACE

#endif /* __SGI_STL_INTERNAL_CONSTRUCT_H */
3.“stl_uninitialized.h”

STL 定义有五个全局函数,作用于未初始化的空间上。分别是:用于构造的函数(construct),用于析构的函数(destroy),uninitialized_copy(),uninitialized_fill(),uninitialized_fill_n()。前两个在 “stl_construct.h” 文件中,剩下三个在本文件中,但其中涉及很多STL算法函数 ---- copy(),fill(),fill_n()(这些在STL算法中详细介绍)。

#ifndef __SGI_STL_INTERNAL_UNINITIALIZED_H
#define __SGI_STL_INTERNAL_UNINITIALIZED_H

__STL_BEGIN_NAMESPACE

// uninitialized_copy 调用 copy constructor

// Valid if copy construction is equivalent to assignment, and if the
//  destructor is trivial.
//对象是POD类型,底层调用 copy()函数
template <class _InputIter, class _ForwardIter>
inline _ForwardIter 
__uninitialized_copy_aux(_InputIter __first, _InputIter __last,
                         _ForwardIter __result,
                         __true_type)
{
  return copy(__first, __last, __result);
}

//对象不是POD类型,循环调用构造函数 _Construct
template <class _InputIter, class _ForwardIter>
_ForwardIter 
__uninitialized_copy_aux(_InputIter __first, _InputIter __last,
                         _ForwardIter __result,
                         __false_type)
{
  _ForwardIter __cur = __result;
  // __STL_TRY 是 try   
  __STL_TRY {
    for ( ; __first != __last; ++__first, ++__cur)
      _Construct(&*__cur, *__first);
    return __cur;
  }
	//  __STL_UNWIND 是 catch ,这里是发生异常后,将销毁 __result
  __STL_UNWIND(_Destroy(__result, __cur));
  // 使用 __STL_TRY 和 __STL_UNWIND 的意义:
  //要么建构出所有元素,要么不建构任何东西,不能存在半建构状态。
}

//判断对象(输出的迭代器)是否是POD类型,如果是第四个参数传:__true_type,如果不是传:__false_type
//何为POD?
// POD(Plain Old Data),指标量型别还是传统的C Struct型别
// POD类型 必须拥有trivial(默认) ctor/dtor/copy/assignment函数
template <class _InputIter, class _ForwardIter, class _Tp>
inline _ForwardIter
__uninitialized_copy(_InputIter __first, _InputIter __last,
                     _ForwardIter __result, _Tp*)
{
  typedef typename __type_traits<_Tp>::is_POD_type _Is_POD;
  return __uninitialized_copy_aux(__first, __last, __result, _Is_POD());
}

// 根据 __result 类型不同,调用不同的 __uninitialized_copy 函数
// 函数意义:把从 __first 到 __last迭代器中指向的数据,复制给以 __result 为开始指向的迭代器。
// [__first, __last)
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
  uninitialized_copy(_InputIter __first, _InputIter __last,
                     _ForwardIter __result)
{
	// __VALUE_TYPE 是“stl_iterator_base.h”一个模板函数,萃取迭代器指向类型,传递不同类型调用不同函数
	//函数返回值是一个类型指针   (这里分析输出的迭代器)
	//template <class _Iter>
	/*inline typename iterator_traits<_Iter>::value_type*
		__value_type(const _Iter&)
	{
		return static_cast<typename iterator_traits<_Iter>::value_type*>(0);
	}*/
  return __uninitialized_copy(__first, __last, __result,
                              __VALUE_TYPE(__result));
}

inline char* uninitialized_copy(const char* __first, const char* __last,
                                char* __result) {
  memmove(__result, __first, __last - __first);
  return __result + (__last - __first);
}

// wchar_t 类型就是 unsigned short 类型;
inline wchar_t* 
uninitialized_copy(const wchar_t* __first, const wchar_t* __last,
                   wchar_t* __result)
{
  memmove(__result, __first, sizeof(wchar_t) * (__last - __first));
  return __result + (__last - __first);
}

// uninitialized_copy_n (not part of the C++ standard)

//输入迭代器,循环调用 构造函数_Construct
template <class _InputIter, class _Size, class _ForwardIter>
pair<_InputIter, _ForwardIter>
__uninitialized_copy_n(_InputIter __first, _Size __count,
                       _ForwardIter __result,
                       input_iterator_tag)
{
  _ForwardIter __cur = __result;
  __STL_TRY {
    for ( ; __count > 0 ; --__count, ++__first, ++__cur) 
      _Construct(&*__cur, *__first);
    return pair<_InputIter, _ForwardIter>(__first, __cur);
  }
  __STL_UNWIND(_Destroy(__result, __cur));
}

//随机访问迭代器
template <class _RandomAccessIter, class _Size, class _ForwardIter>
inline pair<_RandomAccessIter, _ForwardIter>
__uninitialized_copy_n(_RandomAccessIter __first, _Size __count,
                       _ForwardIter __result,
                       random_access_iterator_tag) {
  _RandomAccessIter __last = __first + __count;
  return pair<_RandomAccessIter, _ForwardIter>(
                 __last,
                 uninitialized_copy(__first, __last, __result));
}

//原理同 uninitialized_copy_n 函数
template <class _InputIter, class _Size, class _ForwardIter>
inline pair<_InputIter, _ForwardIter>
__uninitialized_copy_n(_InputIter __first, _Size __count,
                     _ForwardIter __result) {
  return __uninitialized_copy_n(__first, __count, __result,
                                __ITERATOR_CATEGORY(__first));
}

//备注:五种迭代器类型
//1.输入迭代器
//struct input_iterator_tag{}; 
//2.输出迭代器
//struct output_iterator_tag{};
//3.向前迭代器(继承自输入迭代器)
//struct forward_iterator_tag: input_iterator_tag{};
//4.双向迭代器(继承自向前迭代器)
//struct bidirectional_iterator_tag: forward_iterator_tag{};
//5.随机访问迭代器(继承自双向迭代器)
//struct random_access_iterator_tag: bidirectional_iterator_tag{};
//分析:后面三种迭代器3-5类型,都会进行隐式类型转换,转换为input_ierator_tag。

// 根据 __first 类型不同,调用不同的 __uninitialized_copy_n 函数
// 函数意义:把从 __first 开始__count个迭代器中指向的数据,复制给以 __result 为开始指向的迭代器。
// 利用 __ITERATOR_CATEGORY 函数获取 __first 不同类型(标签)的迭代器(这里分析输入的迭代器)
// 不同的迭代器的类型,会针对其有特定的方法实现
template <class _InputIter, class _Size, class _ForwardIter>
inline pair<_InputIter, _ForwardIter>
uninitialized_copy_n(_InputIter __first, _Size __count,
                     _ForwardIter __result) {
  return __uninitialized_copy_n(__first, __count, __result,
                                __ITERATOR_CATEGORY(__first));
}


// Valid if copy construction is equivalent to assignment, and if the
// destructor is trivial.
//是POD 类型的fill 处理方法
template <class _ForwardIter, class _Tp>
inline void
__uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last, 
                         const _Tp& __x, __true_type)
{
  fill(__first, __last, __x);
}

//不是 POD类型的fill 处理方法
template <class _ForwardIter, class _Tp>
void
__uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last, 
                         const _Tp& __x, __false_type)
{
  _ForwardIter __cur = __first;
  __STL_TRY {
    for ( ; __cur != __last; ++__cur)
      _Construct(&*__cur, __x);
  }
  __STL_UNWIND(_Destroy(__first, __cur));
}

//判断输出的迭代器是否是 POD类型
template <class _ForwardIter, class _Tp, class _Tp1>
inline void __uninitialized_fill(_ForwardIter __first, 
                                 _ForwardIter __last, const _Tp& __x, _Tp1*)
{
  typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD;
  __uninitialized_fill_aux(__first, __last, __x, _Is_POD());
                   
}

//函数意义:使用 __x去填充迭代器从 __first 到 __last 中的数据 [__first, __last)
// 利用 __VALUE_TYPE 分析输出的迭代器类型,然后调用不同的最优解(函数)
template <class _ForwardIter, class _Tp>
inline void uninitialized_fill(_ForwardIter __first,
                               _ForwardIter __last, 
                               const _Tp& __x)
{
  __uninitialized_fill(__first, __last, __x, __VALUE_TYPE(__first));
}

// Valid if copy construction is equivalent to assignment, and if the
//  destructor is trivial.
template <class _ForwardIter, class _Size, class _Tp>
inline _ForwardIter
__uninitialized_fill_n_aux(_ForwardIter __first, _Size __n,
                           const _Tp& __x, __true_type)
{
  return fill_n(__first, __n, __x);
}

template <class _ForwardIter, class _Size, class _Tp>
_ForwardIter
__uninitialized_fill_n_aux(_ForwardIter __first, _Size __n,
                           const _Tp& __x, __false_type)
{
  _ForwardIter __cur = __first;
  __STL_TRY {
    for ( ; __n > 0; --__n, ++__cur)
      _Construct(&*__cur, __x);
    return __cur;
  }
  __STL_UNWIND(_Destroy(__first, __cur));
}

//判断输出的迭代器是否是 POD 类型 
template <class _ForwardIter, class _Size, class _Tp, class _Tp1>
inline _ForwardIter 
__uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x, _Tp1*)
{
  typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD;
  return __uninitialized_fill_n_aux(__first, __n, __x, _Is_POD());
}

// 函数意义:把从 __first 开始__n个迭代器中指向的数据,使用 __x 填充。
// __VALUE_TYPE 分析输出的迭代器类型
template <class _ForwardIter, class _Size, class _Tp>
inline _ForwardIter 
uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x)
{
  return __uninitialized_fill_n(__first, __n, __x, __VALUE_TYPE(__first));
}

// Extensions: __uninitialized_copy_copy, __uninitialized_copy_fill, 
// __uninitialized_fill_copy.

// __uninitialized_copy_copy
// 拷贝[first1, last1)到[result, result + (last1 - first1))
// 同时拷贝[first2, last2)到
// [result + (last1 - first1), result + (last1 - first1) + (last2 - first2)]
template <class _InputIter1, class _InputIter2, class _ForwardIter>
inline _ForwardIter
__uninitialized_copy_copy(_InputIter1 __first1, _InputIter1 __last1,
                          _InputIter2 __first2, _InputIter2 __last2,
                          _ForwardIter __result)
{
  _ForwardIter __mid = uninitialized_copy(__first1, __last1, __result);
  __STL_TRY {
    return uninitialized_copy(__first2, __last2, __mid);
  }
  __STL_UNWIND(_Destroy(__result, __mid));
}

// __uninitialized_fill_copy
// 用x填充[result, mid),同时拷贝[first, last)到[mid, mid + (last - first))
template <class _ForwardIter, class _Tp, class _InputIter>
inline _ForwardIter 
__uninitialized_fill_copy(_ForwardIter __result, _ForwardIter __mid,
                          const _Tp& __x,
                          _InputIter __first, _InputIter __last)
{
  uninitialized_fill(__result, __mid, __x);
  __STL_TRY {
    return uninitialized_copy(__first, __last, __mid);
  }
  __STL_UNWIND(_Destroy(__result, __mid));
}

// __uninitialized_copy_fill
// 拷贝[first1, last1)到[first2, first2 + (last1 - first1))
// 并且用x填充[first2 + (last1 - first1), last2)
template <class _InputIter, class _ForwardIter, class _Tp>
inline void
__uninitialized_copy_fill(_InputIter __first1, _InputIter __last1,
                          _ForwardIter __first2, _ForwardIter __last2,
                          const _Tp& __x)
{
  _ForwardIter __mid2 = uninitialized_copy(__first1, __last1, __first2);
  __STL_TRY {
    uninitialized_fill(__mid2, __last2, __x);
  }
  __STL_UNWIND(_Destroy(__first2, __mid2));
}

__STL_END_NAMESPACE

#endif /* __SGI_STL_INTERNAL_UNINITIALIZED_H */
4.“defalloc.h”

上面介绍SGI STL 的配置器叫alloc,但是它也提供了一个标准的allocator,但SGI 并未使用,也不建议我们使用,它只是基层内存配置/释放行为(::operator::new 和 ::operator::delete)的一层薄薄的包装,并没有考虑到任何效率上的强化,只是做了一个兼容。

/* 这是原始的 HP default allocator,提供它只是为了回溯兼容。 */

#ifndef DEFALLOC_H
#define DEFALLOC_H

#include <new.h>
#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
#include <iostream.h>
#include <algobase.h>


template <class T>
inline T* allocate(ptrdiff_t size, T*) {
    set_new_handler(0);   
    // 申请了 (size * sizeof(T)) 大小的空间
    T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
    if (tmp == 0) {
	cerr << "out of memory" << endl; 
	exit(1);
    }
    return tmp;
}


template <class T>
inline void deallocate(T* buffer) {
    ::operator delete(buffer);
}

template <class T>
class allocator {
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;
    pointer allocate(size_type n) { 
	return ::allocate((difference_type)n, (pointer)0);
    }
    void deallocate(pointer p) { ::deallocate(p); }
    pointer address(reference x) { return (pointer)&x; }
    const_pointer const_address(const_reference x) { 
	return (const_pointer)&x; 
    }
    size_type init_page_size() { 
	return max(size_type(1), size_type(4096/sizeof(T))); 
    }
    size_type max_size() const { 
	return max(size_type(1), size_type(UINT_MAX/sizeof(T))); 
    }
};

class allocator<void> {
public:
    typedef void* pointer;
};
#endif

备注:后期源码会上传

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值