一、STL规定的allocator标准
参见侯捷《STL源码剖析》STL规定的allocator标准包含如下功能(方法),当然,并非所有的STL实现版本都严格遵循此标准,因为allocator被STL隐藏,用户一般不直接使用allocator,故而与标准不同也不影响STL的使用。
allocator::value_type
allocator::pointer
allocator::const_pointer
allocator::reference
allocator::const_reference
allocator::size_type
allocator::difference_type
allocator::rebind // 内部类
allocator::allocator()
allocator::allocator(const allocator &)
template <class U> allocator::allocator(const allocator<U>&)
allocator::~allocator()
pointer allocator::address(reference x) const // 传回x的地地,相当于&x,那为什么要搞个函数?
const_pointer allocator::address(const_reference x) const
pointer allocator::allocate(size_type n, const void* = 0)
void allocator::deallocate(pointer p, size_type n)
size_type allocator::max_size() const
void allocator::const(pointer p, const T& x)
void allocator::destroy(pointer p)
二、STLport中对于allocator标准的实现
STLport的allocator位于头文件<_alloc.h>中
template <class _Tp>
class allocator //: public _AllocatorAux<_Tp>
/* A small helper struct to recognize STLport allocator implementation
* from any user specialization one.
*/
: public __stlport_class<allocator<_Tp> >
继承于__stlport_class<allocator<_Tp>>,没什么大作用,暂不讨论。
1. 一此类型的定义
typedef _Tp value_type;
typedef _Tp* pointer;
typedef const _Tp* const_pointer;
typedef _Tp& reference;
typedef const _Tp& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
2. allocator::rebind
#if defined (_STLP_MEMBER_TEMPLATE_CLASSES)
template <class _Tp1> struct rebind {
typedef allocator<_Tp1> other;
};
#endif
定义了另一个allocator<_Tp1>
3. 构造函数
allocator() _STLP_NOTHROW {}
默认构造函数。
allocator(const allocator<_Tp>&) _STLP_NOTHROW {}
复制构造函数。
#if defined (_STLP_MEMBER_TEMPLATES)
template <class _Tp1> allocator(const allocator<_Tp1>&) _STLP_NOTHROW {}
#endif
对于模板是另一个类的复制构造函数。
4. 析构函数
~allocator() _STLP_NOTHROW {}
5. allocator::address()pointer address(reference __x) const {return &__x;}
const_pointer address(const_reference __x) const { return &__x; }
返回了引用参数__x的地址,以指针的形式返回。
6. allocator::allocate()
_Tp* allocate(size_type __n, const void* = 0) {
if (__n > max_size()) {
_STLP_THROW_BAD_ALLOC;
}
if (__n != 0) {
size_type __buf_size = __n * sizeof(value_type);
_Tp* __ret = __REINTERPRET_CAST(_Tp*, __sgi_alloc::allocate(__buf_size)); // 实际分配内存
#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size);
#endif
return __ret;
}
return 0;
}
此函数分配内存。这里__sgi_alloc = __alloc_type = __node_alloc。故而调用了__node_alloc::allocate()
class _STLP_CLASS_DECLSPEC __node_alloc {
static void * _STLP_CALL _M_allocate(size_t& __n);
/* __p may not be 0 */
static void _STLP_CALL _M_deallocate(void *__p, size_t __n);
public:
// this one is needed for proper simple_alloc wrapping
typedef char value_type;
/* __n must be > 0 */
static void* _STLP_CALL allocate(size_t& __n)
{ return (__n > (size_t)_MAX_BYTES) ? __stl_new(__n) : _M_allocate(__n); }
/* __p may not be 0 */
static void _STLP_CALL deallocate(void *__p, size_t __n)
{ if (__n > (size_t)_MAX_BYTES) __stl_delete(__p); else _M_deallocate(__p, __n); }
};
对于此类,STLport文档给出解释:With a reasonable compiler, this should be roughly as fast as the original STL class-specific allocators, but with less fragmentation。
实际分配内存的函数有两个版本:
一是__stl_new,实际就是new。另一是_M_allocate,由__node_alloc::_M_allocate实现。
void * _STLP_CALL __node_alloc::_M_allocate(size_t& __n)
{ return __node_alloc_impl::_M_allocate(__n); }
此实现位于头文件<allocators.cpp>中,看得出,又被封装了一层。
#if !defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
void* __node_alloc_impl::_M_allocate(size_t& __n) {
__n = _S_round_up(__n); // 向上以8字节对齐{ return (((__bytes) + (size_t)_ALIGN-1) & ~((size_t)_ALIGN - 1)); }
_Obj * _STLP_VOLATILE * __my_free_list = _S_free_list + _S_FREELIST_INDEX(__n);
_Obj *__r;
// Acquire the lock here with a constructor call.
// This ensures that it is released in exit or during stack
// unwinding.
_Node_Alloc_Lock __lock_instance;
if ( (__r = *__my_free_list) != 0 ) {
*__my_free_list = __r->_M_next;
} else {
__r = _S_refill(__n);
}
# if defined (_STLP_DO_CLEAN_NODE_ALLOC)
_S_alloc_call();
# endif
// lock is released here
return __r;
}