stl_alloc.h

来源:互联网 发布:淘宝信誉积分怎么刷 编辑:程序博客网 时间:2024/06/11 05:51


#ifndef __SGI_STL_INTERNAL_ALLOC_H#define __SGI_STL_INTERNAL_ALLOC_H#ifdef __SUNPRO_CC#  define __PRIVATE public   // Extra access restrictions prevent us from really making some things   // private.#else#  define __PRIVATE private#endif#ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG#  define __USE_MALLOC#endif// This implements some standard node allocators.  These are// NOT the same as the allocators in the C++ draft standard or in// in the original STL.  They do not encapsulate different pointer// types; indeed we assume that there is only one pointer type.// The allocation primitives are intended to allocate individual objects,// not larger arenas as with the original STL allocators.#ifndef __THROW_BAD_ALLOC#  if defined(__STL_NO_BAD_ALLOC) || !defined(__STL_USE_EXCEPTIONS)#    include <stdio.h>#    include <stdlib.h>#    define __THROW_BAD_ALLOC fprintf(stderr, "out of memory\n"); exit(1)#  else /* Standard conforming out-of-memory handling */#    include <new>#    define __THROW_BAD_ALLOC throw std::bad_alloc()#  endif#endif#include <stddef.h>#include <stdlib.h>#include <string.h>#include <assert.h>#ifndef __RESTRICT#  define __RESTRICT#endif#ifdef __STL_THREADS# include <stl_threads.h># define __NODE_ALLOCATOR_THREADS true# ifdef __STL_SGI_THREADS  // We test whether threads are in use before locking.  // Perhaps this should be moved into stl_threads.h, but that  // probably makes it harder to avoid the procedure call when  // it isn't needed.    extern "C" {      extern int __us_rsthread_malloc;    }    // The above is copied from malloc.h.  Including <malloc.h>    // would be cleaner but fails with certain levels of standard    // conformance.#   define __NODE_ALLOCATOR_LOCK if (threads && __us_rsthread_malloc) \                { _S_node_allocator_lock._M_acquire_lock(); }#   define __NODE_ALLOCATOR_UNLOCK if (threads && __us_rsthread_malloc) \                { _S_node_allocator_lock._M_release_lock(); }# else /* !__STL_SGI_THREADS */#   define __NODE_ALLOCATOR_LOCK \        { if (threads) _S_node_allocator_lock._M_acquire_lock(); }#   define __NODE_ALLOCATOR_UNLOCK \        { if (threads) _S_node_allocator_lock._M_release_lock(); }# endif#else//  Thread-unsafe#   define __NODE_ALLOCATOR_LOCK#   define __NODE_ALLOCATOR_UNLOCK#   define __NODE_ALLOCATOR_THREADS false#endif__STL_BEGIN_NAMESPACE#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)#pragma set woff 1174#endif// Malloc-based allocator.  Typically slower than default alloc below.// Typically thread-safe and more storage efficient.#ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG# ifdef __DECLARE_GLOBALS_HERE    void (* __malloc_alloc_oom_handler)() = 0;    // g++ 2.7.2 does not handle static template data members.# else    extern void (* __malloc_alloc_oom_handler)();# endif#endif//第一级配置template <int __inst>class __malloc_alloc_template {private://oom:out of memory三个处理函数,因为是以malloc(),free(),realloc()等C函数执行实际内存分配释放,所以不能直接使用C++ new-handler机制(set_new_handler()),因为不是用::operator new来分配。//如果未设定处理函数,则抛出std::bad_allocstatic void* _S_oom_malloc(size_t);  static void* _S_oom_realloc(void*, size_t);#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG  static void (* __malloc_alloc_oom_handler)();#endifpublic:  static void* allocate(size_t __n)  {    void* __result = malloc(__n);    if (0 == __result) __result = _S_oom_malloc(__n);    return __result;  }  static void deallocate(void* __p, size_t /* __n */)  {    free(__p);  }  static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz)  {    void* __result = realloc(__p, __new_sz);    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 out-of-memory handling#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUGtemplate <int __inst>void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0;#endiftemplate <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;        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);    }}typedef __malloc_alloc_template<0> malloc_alloc;//   allocate->_S_oom_malloc->__malloc_alloc_oom_handler//   reallocate->_S_oom_realloc->__malloc_alloc_oom_handler//--------------------------------------------------------------------------------------------------//外面再多一层封装,使Alloc具备标准接口template<class _Tp, class _Alloc>class simple_alloc {public:    static _Tp* allocate(size_t __n)      { return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof (_Tp)); }    static _Tp* allocate(void)      { return (_Tp*) _Alloc::allocate(sizeof (_Tp)); }    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)); }};// 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.//带有debug功能的allocator适配器//新分配地址的头部额外多增加8个字节,用来存放新分配空间的大小,dealloate和reallocate会验证传入的释放空间大小是否等于待释放地址头部8个字节存放的空间大小,//如果不相等,则abort。template <class _Alloc>class debug_alloc {private:  enum {_S_extra = 8};   //存储分配空间大小所需的位数public:  static void* allocate(size_t __n)  {    char* __result = (char*)_Alloc::allocate(__n + (int) _S_extra);    *(size_t*)__result = __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;  }};# ifdef __USE_MALLOCtypedef malloc_alloc alloc;typedef malloc_alloc single_client_alloc;# else//  Sun C++ compiler需要在类外定义这些枚举  #if defined(__SUNPRO_CC) || defined(__GNUC__)// breaks if we make these template class members:  enum {_ALIGN = 8};       //小型区块的上调边界  enum {_MAX_BYTES = 128}; //小型区块的上限  enum {_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN   free-lists 个数#endif//第二级配置器// 默认的node allocator  // 如果有合适的编译器, 速度上与原始的STL class-specific allocators大致等价 // 但是具有产生更少内存碎片的优点  // Default_alloc_template参数是用于实验性质的, 在未来可能会消失 // 客户只能在当下使用alloc  //  // 重要的实现属性:  // 1. 如果客户请求一个size > __MAX_BYTE的对象, 则直接使用malloc()分配 // 2. 对于其它情况下, 我们将请求对象的大小按照内存对齐向上舍入ROUND_UP(requested_size)   //    Thus the client has enough size information that we can return the object to the proper free list  //    without permanently losing part of the object.  //    //  第一个模板参数指定是否有多于一个线程使用本allocator  // 在一个default_alloc实例中分配对象, 在另一个deallocate实例中释放对象, 是安全的 // 这有效的转换其所有权到另一个对象 // 这可能导致对我们引用的区域产生不良影响 // 第二个模板参数仅仅用于创建多个default_alloc实例 // 不同容器使用不同allocator实例创建的node拥有不同类型, 这限制了此方法的通用性   //allocate()大于128调用第一级适配器,否则在free-list中找,没找到调用refill()从内存池中填充到free-list //refill()调用chunk_alloc从内存池中取空间给free-list使用,然后调整free-list链表 //内存池中有20个或有但不满20个,则调整内存池的起始位置,返回内存地址, //内存池中一个也不能满足了,则如果内存池中还要剩余的一些零头,则编入free-list,然后尝试从heap分配40+n块空间到内存池。分配成功后递归调用返回空间地址//heap上也没有空间分配了,则先检查free-list中有没比所需块大一点的空间,有则分配给他,堆上也没有则调用第一级配置器,改善或排除异常。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.#if ! (defined(__SUNPRO_CC) || defined(__GNUC__))    enum {_ALIGN = 8};    enum {_MAX_BYTES = 128};    enum {_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN# endif  static size_t  _S_round_up(size_t __bytes)          //向上调整至的倍数    { return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); }__PRIVATE:  union _Obj {        union _Obj* _M_free_list_link;        char _M_client_data[1];    /* The client sees this.        */  //柔性数组  };/*int main(){    _Obj* test = (_Obj*)"12345678";    cout << sizeof(_Obj) <<endl;       //4    cout<<test->_M_client_data<<endl;  //"12345678"    return 0;}*/private:# if defined(__SUNPRO_CC) || defined(__GNUC__) || defined(__HP_aCC)    static _Obj* __STL_VOLATILE _S_free_list[];           ////volatile关键字,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。        // Specifying a size results in duplicate def for 4.1# else    static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS]; # endif  static  size_t _S_freelist_index(size_t __bytes) { //根据区块大小,使用第n号free-list        return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1);//向上取,再减1  } // // 返回一个大小为n的对象,并可能加入大小为n的其他区块到free-list  static void* _S_refill(size_t __n); //配置一大块空间,可容纳nobjs个大小为size的区块 //如果配置nobjs个区块有所不便,nobjs可能会减小  static char* _S_chunk_alloc(size_t __size, int& __nobjs);  // Chunk allocation state.  static char* _S_start_free;  // 内存池起始点  static char* _S_end_free;    // 内存池结束点  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.    class _Lock;    friend class _Lock;    class _Lock {        public:            _Lock() { __NODE_ALLOCATOR_LOCK; }            ~_Lock() { __NODE_ALLOCATOR_UNLOCK; }    };public:  /* __n must be > 0      */  static void* allocate(size_t __n)  {    void* __ret = 0;    // 如果待分配对象大于__MAX_BYTES, 使用一级配置器分配      if (__n > (size_t) _MAX_BYTES) {      __ret = malloc_alloc::allocate(__n);    }    else {      _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;      //没有可用区块,就填充空间      if (__result == 0)        __ret = _S_refill(_S_round_up(__n));      else {        *__my_free_list = __result -> _M_free_list_link;        __ret = __result;      }    }    return __ret;  };  /* __p may not be 0 */  static void deallocate(void* __p, size_t __n)  {    if (__n > (size_t) _MAX_BYTES)      malloc_alloc::deallocate(__p, __n);    else {      _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;//任意两个allocator都是可互换的;如果a1和a2的类型都是allocator,我们可以自由地通过a1来allocate()内存然后通过 a2来deallocate()它。//我们因此定义一个比较操作以表明所有allocator对象是等价的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_ORDERtemplate <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 */// 每次分配一大块内存, 防止多次分配小内存块带来的内存碎片  // 进行分配操作时, 根据具体环境决定是否加锁 // 我们假定要分配的内存满足内存对齐要求 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;  // 计算内存池剩余容量         //  如果内存池中剩余内存>=需要分配的内内存, 返回start_free指向的内存块,      // 并且重新设置内存池起始点     if (__bytes_left >= __total_bytes) {        __result = _S_start_free;        _S_start_free += __total_bytes;        return(__result);    }     // 如果内存吃中剩余的容量不够分配, 但是能至少分配一个节点时,       // 返回所能分配的最多的节点, 返回start_free指向的内存块     // 并且重新设置内存池起始点     else if (__bytes_left >= __size) {        __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.        // 将剩余的内存分配给指定的free_list[FREELIST_INDEX(bytes_left)]  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;        }        //配置heap空间,补充内存池        _S_start_free = (char*)malloc(__bytes_to_get);        if (0 == _S_start_free) {  //malloc()失败            size_t __i;            _Obj* __STL_VOLATILE* __my_free_list;        _Obj* __p;                       //尝试检查我们手上拥有的东西,这不会造成伤害。我们不打算尝试配置较小的区块。           //因为那在多进程机器上容易造成灾难                      //以下搜寻未使用的比size大的free-list区块            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) { //有未用区块则调整free-list以释出未用区块                    *__my_free_list = __p -> _M_free_list_link;                    _S_start_free = (char*)__p;                    _S_end_free = _S_start_free + __i;                    //递归调用自己,以修正nobjs                    return(_S_chunk_alloc(__size, __nobjs));                    //注意,残余零头终将被编入适当的free-list中备用                }            }             _S_end_free = 0;    // In case of exception.            _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);             //调用第一级配置器,看看out-of-memory机制能否尽力,或抛出异常。        }        _S_heap_size += __bytes_to_get;        _S_end_free = _S_start_free + __bytes_to_get;        return(_S_chunk_alloc(__size, __nobjs));    }}//  返回一个大小为n的对象, 并且加入到free_list[FREELIST_INDEX(n)]  // 进行分配操作时, 根据具体环境决定是否加锁  // 我们假定要分配的内存满足内存对齐要求template <bool __threads, int __inst>void*__default_alloc_template<__threads, __inst>::_S_refill(size_t __n){    int __nobjs = 20;    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);    __my_free_list = _S_free_list + _S_freelist_index(__n);    /* Build free list in chunk */      __result = (_Obj*)__chunk;      *__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;    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;#endiftemplate <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 */// This implements allocators as specified in the C++ standard.  //// Note that standard-conforming allocators use many language features// that are not yet widely implemented.  In particular, they rely on// member templates, partial specialization, partial ordering of function// templates, the typename keyword, and the use of the template keyword// to refer to a template member of a dependent type.#ifdef __STL_USE_STD_ALLOCATORStemplate <class _Tp>class allocator {  typedef alloc _Alloc;          // The underlying 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 <class _Tp1> struct rebind {    typedef allocator<_Tp1> other;  };  allocator() __STL_NOTHROW {}  allocator(const allocator&) __STL_NOTHROW {}  template <class _Tp1> allocator(const allocator<_Tp1>&) __STL_NOTHROW {}  ~allocator() __STL_NOTHROW {}  pointer address(reference __x) const { return &__x; }  const_pointer address(const_reference __x) const { return &__x; }  // __n is permitted to be 0.  The C++ standard says nothing about what  // the return value is when __n == 0.  _Tp* allocate(size_type __n, const void* = 0) {    return __n != 0 ? static_cast<_Tp*>(_Alloc::allocate(__n * sizeof(_Tp)))                     : 0;  }  // __p is not permitted to be a null pointer.  void deallocate(pointer __p, size_type __n)    { _Alloc::deallocate(__p, __n * sizeof(_Tp)); }  size_type max_size() const __STL_NOTHROW     { return size_t(-1) / sizeof(_Tp); }  void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }  void destroy(pointer __p) { __p->~_Tp(); }};template<>class allocator<void> {public:  typedef size_t      size_type;  typedef ptrdiff_t   difference_type;  typedef void*       pointer;  typedef const void* const_pointer;  typedef void        value_type;  template <class _Tp1> struct rebind {    typedef allocator<_Tp1> other;  };};template <class _T1, class _T2>inline bool operator==(const allocator<_T1>&, const allocator<_T2>&) {  return true;}template <class _T1, class _T2>inline bool operator!=(const allocator<_T1>&, const allocator<_T2>&){  return false;}// Allocator adaptor to turn an SGI-style allocator (e.g. alloc, malloc_alloc)// into a standard-conforming allocator.   Note that this adaptor does// *not* assume that all objects of the underlying alloc class are// identical, nor does it assume that all of the underlying alloc's// member functions are static member functions.  Note, also, that // __allocator<_Tp, alloc> is essentially the same thing as allocator<_Tp>.template <class _Tp, class _Alloc>struct __allocator {  _Alloc __underlying_alloc;  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 <class _Tp1> struct rebind {    typedef __allocator<_Tp1, _Alloc> other;  };  __allocator() __STL_NOTHROW {}  __allocator(const __allocator& __a) __STL_NOTHROW    : __underlying_alloc(__a.__underlying_alloc) {}  template <class _Tp1>   __allocator(const __allocator<_Tp1, _Alloc>& __a) __STL_NOTHROW    : __underlying_alloc(__a.__underlying_alloc) {}  ~__allocator() __STL_NOTHROW {}  pointer address(reference __x) const { return &__x; }  const_pointer address(const_reference __x) const { return &__x; }  // __n is permitted to be 0.  _Tp* allocate(size_type __n, const void* = 0) {    return __n != 0         ? static_cast<_Tp*>(__underlying_alloc.allocate(__n * sizeof(_Tp)))         : 0;  }  // __p is not permitted to be a null pointer.  void deallocate(pointer __p, size_type __n)    { __underlying_alloc.deallocate(__p, __n * sizeof(_Tp)); }  size_type max_size() const __STL_NOTHROW     { return size_t(-1) / sizeof(_Tp); }  void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }  void destroy(pointer __p) { __p->~_Tp(); }};template <class _Alloc>class __allocator<void, _Alloc> {  typedef size_t      size_type;  typedef ptrdiff_t   difference_type;  typedef void*       pointer;  typedef const void* const_pointer;  typedef void        value_type;  template <class _Tp1> struct rebind {    typedef __allocator<_Tp1, _Alloc> other;  };};template <class _Tp, class _Alloc>inline bool operator==(const __allocator<_Tp, _Alloc>& __a1,                       const __allocator<_Tp, _Alloc>& __a2){  return __a1.__underlying_alloc == __a2.__underlying_alloc;}#ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDERtemplate <class _Tp, class _Alloc>inline bool operator!=(const __allocator<_Tp, _Alloc>& __a1,                       const __allocator<_Tp, _Alloc>& __a2){  return __a1.__underlying_alloc != __a2.__underlying_alloc;}#endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER */// Comparison operators for all of the predifined SGI-style allocators.// This ensures that __allocator<malloc_alloc> (for example) will// work correctly.template <int inst>inline bool operator==(const __malloc_alloc_template<inst>&,                       const __malloc_alloc_template<inst>&){  return true;}#ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDERtemplate <int __inst>inline bool operator!=(const __malloc_alloc_template<__inst>&,                       const __malloc_alloc_template<__inst>&){  return false;}#endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER */template <class _Alloc>inline bool operator==(const debug_alloc<_Alloc>&,                       const debug_alloc<_Alloc>&) {  return true;}#ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDERtemplate <class _Alloc>inline bool operator!=(const debug_alloc<_Alloc>&,                       const debug_alloc<_Alloc>&) {  return false;}#endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER */// Another allocator adaptor: _Alloc_traits.  This serves two// purposes.  First, make it possible to write containers that can use// either SGI-style allocators or standard-conforming allocator.// Second, provide a mechanism so that containers can query whether or// not the allocator has distinct instances.  If not, the container// can avoid wasting a word of memory to store an empty object.// This adaptor uses partial specialization.  The general case of// _Alloc_traits<_Tp, _Alloc> assumes that _Alloc is a// standard-conforming allocator, possibly with non-equal instances// and non-static members.  (It still behaves correctly even if _Alloc// has static member and if all instances are equal.  Refinements// affect performance, not correctness.)// There are always two members: allocator_type, which is a standard-// conforming allocator type for allocating objects of type _Tp, and// _S_instanceless, a static const member of type bool.  If// _S_instanceless is true, this means that there is no difference// between any two instances of type allocator_type.  Furthermore, if// _S_instanceless is true, then _Alloc_traits has one additional// member: _Alloc_type.  This type encapsulates allocation and// deallocation of objects of type _Tp through a static interface; it// has two member functions, whose signatures are//    static _Tp* allocate(size_t)//    static void deallocate(_Tp*, size_t)// The fully general version./*另一个allocator适配器_Alloc_traits, 它有两个意图  1.使容易既看使用sgi风格的allocator,也可以使用标准规格的allocator  2.提供了一种机制:容器可以查询allocator是否拥有明确的实体,如果没有,容易可以避免浪费内存去存储空对象这个适配器使用了偏特化。_Alloc_traits<_Tp, _Alloc>假定_Alloc是一个服从标准的allocator,可能有不相等的实例和非静态成员。(如果各实例相等或拥有静态成员,也表现正确。 优化影响执行效率,不影响正确性)有两个成员1. allocator_type 服从标准的分配_Tp类型对象的allocator类型2. _S_instanceless一个static const bool成员   如果为true,则表示任何两个allocator_type实例之间没有差别,同时,_Alloc_traits有额外的成员_Alloc_type_Alloc_type通过一个静态接口封装了分配和回收_Tp类型对象,它有两个成员函数,原型为 static _Tp* allocate(size_t) static void deallocate(_Tp*, size_t)*///写自定义分配器的时候也是,必须重写rebind,且不能有非静态成员。并假定任何同类型的allocator相等,即_S_instanceless为truetemplate <class _Tp, class _Allocator>struct _Alloc_traits{  static const bool _S_instanceless = false;  typedef typename _Allocator::__STL_TEMPLATE rebind<_Tp>::other           allocator_type;};template <class _Tp, class _Allocator>const bool _Alloc_traits<_Tp, _Allocator>::_S_instanceless;// The version for the default allocator.//给默认allocator的版本template <class _Tp, class _Tp1>struct _Alloc_traits<_Tp, allocator<_Tp1> >{  static const bool _S_instanceless = true;  typedef simple_alloc<_Tp, alloc> _Alloc_type;  typedef allocator<_Tp> allocator_type;};// Versions for the predefined SGI-style allocators.template <class _Tp, int __inst>struct _Alloc_traits<_Tp, __malloc_alloc_template<__inst> >{  static const bool _S_instanceless = true;  typedef simple_alloc<_Tp, __malloc_alloc_template<__inst> > _Alloc_type;  typedef __allocator<_Tp, __malloc_alloc_template<__inst> > allocator_type;};template <class _Tp, bool __threads, int __inst>struct _Alloc_traits<_Tp, __default_alloc_template<__threads, __inst> >{  static const bool _S_instanceless = true;  typedef simple_alloc<_Tp, __default_alloc_template<__threads, __inst> >           _Alloc_type;  typedef __allocator<_Tp, __default_alloc_template<__threads, __inst> >           allocator_type;};template <class _Tp, class _Alloc>struct _Alloc_traits<_Tp, debug_alloc<_Alloc> >{  static const bool _S_instanceless = true;  typedef simple_alloc<_Tp, debug_alloc<_Alloc> > _Alloc_type;  typedef __allocator<_Tp, debug_alloc<_Alloc> > allocator_type;};// Versions for the __allocator adaptor used with the predefined// SGI-style allocators.template <class _Tp, class _Tp1, int __inst>struct _Alloc_traits<_Tp,                      __allocator<_Tp1, __malloc_alloc_template<__inst> > >{  static const bool _S_instanceless = true;  typedef simple_alloc<_Tp, __malloc_alloc_template<__inst> > _Alloc_type;  typedef __allocator<_Tp, __malloc_alloc_template<__inst> > allocator_type;};template <class _Tp, class _Tp1, bool __thr, int __inst>struct _Alloc_traits<_Tp,                       __allocator<_Tp1,                                   __default_alloc_template<__thr, __inst> > >{  static const bool _S_instanceless = true;  typedef simple_alloc<_Tp, __default_alloc_template<__thr,__inst> >           _Alloc_type;  typedef __allocator<_Tp, __default_alloc_template<__thr,__inst> >           allocator_type;};template <class _Tp, class _Tp1, class _Alloc>struct _Alloc_traits<_Tp, __allocator<_Tp1, debug_alloc<_Alloc> > >{  static const bool _S_instanceless = true;  typedef simple_alloc<_Tp, debug_alloc<_Alloc> > _Alloc_type;  typedef __allocator<_Tp, debug_alloc<_Alloc> > allocator_type;};#endif /* __STL_USE_STD_ALLOCATORS */#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)#pragma reset woff 1174#endif__STL_END_NAMESPACE#undef __PRIVATE#endif /* __SGI_STL_INTERNAL_ALLOC_H */// Local Variables:// mode:C++// End:


0 0
原创粉丝点击