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
- stl_alloc.h
- stl_alloc.h
- Stl_alloc.h
- stl_alloc.h
- stl_alloc.h
- 《STL源码剖析》-- stl_alloc.h
- 《STL源码剖析》--stl_alloc.h
- 《STL源码剖析》---stl_alloc.h阅读笔记
- C++ STL源码剖析——stl_alloc.h
- STL源码剖析 [特殊的空间配置器](内存配置stl_alloc.h)
- h
- h
- h
- ,h
- h
- h
- H
- h
- Kafka系列之-Kafka Protocol实例分析
- 欢迎使用CSDN-markdown编辑器
- 漫步数学分析十二——嵌套
- 网页编辑器kindeditor的使用
- JAVA-for循环语句
- stl_alloc.h
- 使用jquery的delegate进行多项绑定
- 明明的随机数
- 利用xcodeproj修改xcode工程文件
- mysql 协议的初始化DB命令包及解析
- caffe网络结构可视化
- spring+websocket整合(springMVC+spring+MyBatis即SSM框架和websocket技术的整合)
- SpringMVC Controller中常用到的一些注解
- 关于AsyncQueryHandler偶尔数据不更新问题