#endif
allocator(const allocator<_Tp>&) _STLP_NOTHROW {}
#if !defined (_STLP_NO_MOVE_SEMANTIC)
allocator(__move_source
#endif
~allocator() _STLP_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) {
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;
}
// __p is permitted to be a null pointer, only if n==0.
void deallocate(pointer __p, size_type __n) {
_STLP_ASSERT( (__p == 0) == (__n == 0) )
if (__p != 0) {
#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
memset((char*)__p, _STLP_SHRED_BYTE, __n * sizeof(value_type));
#endif
__sgi_alloc::deallocate((void*)__p, __n * sizeof(value_type));
}
}
#if !defined (_STLP_NO_ANACHRONISMS)
// backwards compatibility
void deallocate(pointer __p) const { if (__p != 0) __sgi_alloc::deallocate((void*)__p, sizeof(value_type)); }
#endif
size_type max_size() const _STLP_NOTHROW { return size_t(-1) / sizeof(value_type); }
void construct(pointer __p, const_reference __val) { _STLP_STD::_Copy_Construct(__p, __val); }
void destroy(pointer __p) { _STLP_STD::_Destroy(__p); }
#if defined (_STLP_NO_EXTENSIONS)
/* STLport extension giving rounded size of an allocated memory buffer
* This method do not have to be part of a user defined allocator implementation
* and won't even be called if such a function was granted.
*/
protected:
#endif
_Tp* _M_allocate(size_type __n, size_type& __allocated_n) {
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
__allocated_n = __buf_size / sizeof(value_type);
return __ret;
}
return 0;
}
#if defined (_STLP_USE_PARTIAL_SPEC_WORKAROUND) && !defined (_STLP_FUNCTION_TMPL_PARTIAL_ORDER)
void _M_swap_workaround(allocator<_Tp>& __other) {}
#endif
};
在我调试的时候是用内存分配函数_M_allocate来从内存池(按侯先生的说法是空间,不一定是内存)中分配可用空间到自由链以及返回用户使用。若想更进一步了解,必须自己去看源代码:RTFSC。小结一下,SGI 的这份代码符合标准规范,结合侯先生的书,可以让你看清STL的实现本质。
3. 最后说一下ACE的allocator实现。应该说,ACE的实现可能在设计的时候,就不打算遵守C++标准库的规范,只是为了高效安全的在ACE内部使用。我们也可以看以下接口代码。基类ACE_Allocator直接使用了malloc和free让子类去实现。这份代码完全可以结合侯先生的书来看,只是在一些实现的名字前面加上ACE或者_S等前缀,实现的原理和SGI是很相似的。在内存块管理方面,小块内存(小于128),也是用自由链去管理,大块内存(大于128)直接分配。在自由链表方面它也使用了一个和SGI一样的小技巧,就是把next指针放在未使用内存块的开头处(我第一次看到这种技巧,有点怪怪的,但是能很好的实现,主要是效率有提升,多少就不考究了)。比SGI加多了一个block块链的管理,可以更灵活的使用(应该是限于ACE的应用了,因为它不遵守标准)。
[cpp]
class ACE_Export ACE_Allocator
{
public:
/// Unsigned integer type used for specifying m