STL内存创建
Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 转载请标明来源
1. Stl内存创建基类模板__malloc_alloc_template
STL的经常使用的内存创建參考文件: stl_alloc.h,文件里定义了__malloc_alloc_template模板库,创建与释放使用C方法malloc、free、realloc,模板库里面主要对外提供了函数:
allocate: 分配内存
deallocate: 释放内存
reallocate: 又一次分配内存
__set_malloc_handler: 设置异常处理函数
template <int __inst> class __malloc_alloc_template {
private:
static 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)(); #endif
public:
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); }
}; |
2. 内存分配与释放
使用malloc和realloc分配内存,对于分配内存异常的处理,模板库中交给内部的这两个静态方法:
_S_oom_malloc
_S_oom_ realloc
使用free释放内存,对于释放内存来说,是无异常处理的,直接调用free指针,传入的size_t未使用。
3 分配异常处理
分配内存的异常处理方法,參考_S_oom_malloc/_S_oom_realloc中的实现
在实现中或者是通过抛出异常,或者是通过运行约定的处理函数(如内存整理函数),然后继续申请内存。
在以下的函数中,涉及了函数指针:
__malloc_alloc_oom_handler
这个函数指定方法__malloc_alloc_template ::__set_malloc_handler
假设这个函数未指定的话,调用异常__THROW_BAD_ALLOC处理
a. C++下,抛出std::bad_alloc(),
b. C下,向标准输出中打印并终止程序: fprintf(stderr, "out of memory "); exit(1)
假设这个函数指定的话,指行这个函数(比如内存整理函数),然后再次申请内存,直到成功申请到后返回申请到的内存地址:
__my_malloc_handler = __malloc_alloc_oom_handler;
(*__my_malloc_handler)();
__result = malloc(__n);
if (__result) return(__result);
#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 "); exit(1) # else /* Standard conforming out-of-memory handling */ # include <new> # define __THROW_BAD_ALLOC throw std::bad_alloc() # endif #endif #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG 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; 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); } } |
4. 封装的几组分配方式
a. Simple_alloc,附加了检查0/NULL的操作
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)); } }; |
b. debug_alloc每次分配时,多附加8字节的空间,用于存储当前分配的size大小。
// 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. template <class _Alloc> class debug_alloc { private: enum {_S_extra = 8}; // Size of space used to store size. Note // that this must be large enough to preserve // alignment. 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; } }; |
5. 内存分配类allocator/__allocator
allocator分配类使用缺省的分配类(alloc),使用分配类的静态方法。
__allocator类须要输入分配类,并对分配类实例化了对像,调用对像的分配方法分配内存。
a) allocator
// 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_ALLOCATORS template <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(); } }; |
b) __allocator
能够传入不同的分配方式,另外实例化了对像,支持对象内记录分配字节等,属于对复杂分配方式的支的。
__allocator最大的特点,实例化了分配对像
// 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(); } }; |
6. 内存分配结构体
这个结构体非常有意思,
參数一: _S_instanceless标识包括有allocator_type定义
參数二: _Alloc_type,简单分配方式,simple_alloc调用_Alloc的静态方法进行分配释放内存
參数三: allocator_type,可支持复杂分配方式,实例化了_Alloc对像,使用对象方法分配释放内存,支持对象内包括分配的总数,或其他附加信息,能够在对像内实现内存池等。
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; }; |