由于std::set,std::multiset,std::map,std::multimap四种容器的插入删除操作性能高并且自动排序,在很多时候比如需要动态操作时往往会使用它们,然后由于容器内部使用的是节点,每次的插入或删除都要调用new或delete,往往容易造成碎片和性能下降,于是自定义的allocator出现了。
这篇文章的目的就是详细讲解std::allocator的内部结构,为实现自定义的allocator奠基。
贴出STL源码,通过增加注释讲解
// 说明:std::allocator将内存分配与释放、对象的构造与销毁独立出来,
// 分别为内存分配、对象构造、对象销毁、内存释放。
#pragma pack(push,_CRT_PACKING)
#pragma warning(push,3)
#define _ALLOCATOR allocator
// 由于下方使用了operator new函数,因此需要先取消new的宏定义
#pragma push_macro("new")
#undef new
#pragma warning(disable: 4100)
#ifndef _FARQ /* specify standard memory model */
#define _FARQ
#define _PDFT ptrdiff_t
#define _SIZT size_t
#endif /* _FARQ */
_STD_BEGIN
// 这里是内存分配
// TEMPLATE FUNCTION _Allocate
template<class _Ty> inline
_Ty _FARQ *_Allocate(_SIZT _Count, _Ty _FARQ *)
{ // allocate storage for _Count elements of type _Ty
void *_Ptr = 0;
if (_Count <= 0)
_Count = 0;
else if (((_SIZT)(-1) / sizeof (_Ty) < _Count)
|| (_Ptr = ::operator new(_Count * sizeof (_Ty))) == 0)
_THROW_NCEE(bad_alloc, 0);
return ((_Ty _FARQ *)_Ptr);
}
// 使用 placement new 进行对象的拷贝构造放置
// TEMPLATE FUNCTION _Construct
template<class _Ty1,
class _Ty2> inline
void _Construct(_Ty1 _FARQ *_Ptr, _Ty2&& _Val)
{ // construct object at _Ptr with value _Val
void _FARQ *_Vptr = _Ptr;
::new (_Vptr) _Ty1(_STD forward<_Ty2>(_Val));
}
// 使用 placement new 进行对象的默认构造放置
template<class _Ty1> inline
void _Construct(_Ty1 _FARQ *_Ptr)
{ // construct object at _Ptr with default value
void _FARQ *_Vptr = _Ptr;
::new (_Vptr) _Ty1();
}
// 对象销毁(析构函数)
// TEMPLATE FUNCTION _Destroy
template<class _Ty> inline
void _Destroy(_Ty _FARQ *_Ptr)
{ // destroy object at _Ptr
_Ptr->~_Ty();
}
// 内嵌字符串类型不用析构,特化版本供优化使用
template<> inline
void _Destroy(char _FARQ *)
{ // destroy a char (do nothing)
}
template<> inline
void _Destroy(wchar_t _FARQ *)
{ // destroy a wchar_t (do nothing)
}
#ifdef _NATIVE_WCHAR_T_DEFINED
template<> inline
void _Destroy(unsigned short _FARQ *)
{ // destroy a unsigned short (do nothing)
}
#endif /* _NATIVE_WCHAR_T_DEFINED */
// 根据指针类型选择是否为 POD 数据类型
// TEMPLATE FUNCTION _Destroy_range
template<class _Alloc> inline
void _Destroy_range(typename _Alloc::pointer _First,
typename _Alloc::pointer _Last, _Alloc& _Al)
{ // destroy [_First, _Last)
_Destroy_range(_First, _Last, _Al, _Ptr_cat(_First, _Last));
}
// 非 POD 数据类型需要显示调用析构函数
template<class _Alloc> inline
void _Destroy_range(typename _Alloc::pointer _First,
typename _Alloc::pointer _Last, _Alloc& _Al,
_Nonscalar_ptr_iterator_tag)
{ // destroy [_First, _Last), arbitrary type
for (; _First != _Last; ++_First)
_Dest_val(_Al, _First);
}
// POD 数据类型不需要调用析构函数
template<class _Alloc> inline
void _Destroy_range(typename _Alloc::pointer _First,
typename _Alloc::pointer _Last, _Alloc& _Al,
_Scalar_ptr_iterator_tag)
{ // destroy [_First, _Last), scalar type (do nothing)
}
// TEMPLATE FUNCTION addressof
template<class _Ty> inline
_Ty * addressof(_Ty& _Val)
{ // return address of _Val
return ((_Ty *) &(char&)_Val);
}
// TEMPLATE CLASS _Allocator_base
template<class _Ty>
struct _Allocator_base
{ // base class for generic allocators
typedef _Ty value_type;
};
// 偏特化,去除 const 属性
// TEMPLATE CLASS _Allocator_base<const _Ty>
template<class _Ty>
struct _Allocator_base<const _Ty>
{ // base class for generic allocators for const _Ty
typedef _Ty value_type;
};
// TEMPLATE CLASS _ALLOCATOR
template<class _Ty>
class _ALLOCATOR
: public _Allocator_base<_Ty>
{ // generic allocator for objects of class _Ty
public:
typedef _Allocator_base<_Ty> _Mybase;
typedef typename _Mybase::value_type value_type;
typedef value_type _FARQ *pointer;
typedef value_type _FARQ& reference;
typedef const value_type _FARQ *const_pointer;
typedef const value_type _FARQ& const_reference;
typedef _SIZT size_type;
typedef _PDFT difference_type;
// 由于在STL容器中allocator是以模板参数传入的,而对于节点型容器,
// 如list, set, map,需要重新绑定数据结构,因而 rebind 便会用到
template<class _Other>
struct rebind
{ // convert this type to _ALLOCATOR<_Other>
typedef _ALLOCATOR<_Other> other;
};
pointer address(reference _Val) const
{ // return address of mutable _Val
return ((pointer) &(char&)_Val);
}
const_pointer address(const_reference _Val) const
{ // return address of nonmutable _Val
return ((const_pointer) &(char&)_Val);
}
_ALLOCATOR() _THROW0()
{ // construct default allocator (do nothing)
}
_ALLOCATOR(const _ALLOCATOR<_Ty>&) _THROW0()
{ // construct by copying (do nothing)
}
// 这里使用了 Coercion by Member Template 惯用法
template<class _Other>
_ALLOCATOR(const _ALLOCATOR<_Other>&) _THROW0()
{ // construct from a related allocator (do nothing)
}
// 这里使用了 Coercion by Member Template 惯用法
template<class _Other>
_ALLOCATOR<_Ty>& operator=(const _ALLOCATOR<_Other>&)
{ // assign from a related allocator (do nothing)
return (*this);
}
// 内存释放
void deallocate(pointer _Ptr, size_type)
{ // deallocate object at _Ptr, ignore size
::operator delete(_Ptr);
}
// 内存分配
pointer allocate(size_type _Count)
{ // allocate array of _Count elements
return (_Allocate(_Count, (pointer)0));
}
pointer allocate(size_type _Count, const void _FARQ *)
{ // allocate array of _Count elements, ignore hint
return (allocate(_Count));
}
void construct(pointer _Ptr, const _Ty& _Val)
{ // construct object at _Ptr with value _Val
_Construct(_Ptr, _Val);
}
// placement new
void construct(pointer _Ptr, _Ty&& _Val)
{ // construct object at _Ptr with value _Val
::new ((void _FARQ *)_Ptr) _Ty(_STD forward<_Ty>(_Val));
}
template<class _Other>
void construct(pointer _Ptr, _Other&& _Val)
{ // construct object at _Ptr with value _Val
::new ((void _FARQ *)_Ptr) _Ty(_STD forward<_Other>(_Val));
}
// 对象销毁
void destroy(pointer _Ptr)
{ // destroy object at _Ptr
_Destroy(_Ptr);
}
_SIZT max_size() const _THROW0()
{ // estimate maximum array size
_SIZT _Count = (_SIZT)(-1) / sizeof (_Ty);
return (0 < _Count ? _Count : 1);
}
};
// 特化版本,void 类型通常是无意义的
// CLASS _ALLOCATOR<void>
template<> class _ALLOCATOR<void>
{ // generic _ALLOCATOR for type void
public:
typedef void _Ty;
typedef _Ty _FARQ *pointer;
typedef const _Ty _FARQ *const_pointer;
typedef _Ty value_type;
// rebind 必须重定义
template<class _Other>
struct rebind
{ // convert this type to an _ALLOCATOR<_Other>
typedef _ALLOCATOR<_Other> other;
};
_ALLOCATOR() _THROW0()
{ // construct default allocator (do nothing)
}
_ALLOCATOR(const _ALLOCATOR<_Ty>&) _THROW0()
{ // construct by copying (do nothing)
}
template<class _Other>
_ALLOCATOR(const _ALLOCATOR<_Other>&) _THROW0()
{ // construct from related allocator (do nothing)
}
template<class _Other>
_ALLOCATOR<_Ty>& operator=(const _ALLOCATOR<_Other>&)
{ // assign from a related allocator (do nothing)
return (*this);
}
};
// allocator内部由于没有数据,因而总是相同的功能
template<class _Ty,
class _Other> inline
bool operator==(const allocator<_Ty>&,
const allocator<_Other>&) _THROW0()
{ // test for allocator equality
return (true);
}
template<class _Ty,
class _Other> inline
bool operator!=(const allocator<_Ty>& _Left,
const allocator<_Other>& _Right) _THROW0()
{ // test for allocator inequality
return (!(_Left == _Right));
}
// TEMPLATE FUNCTIONS _Cons_val AND _Dest_val
template<class _Alloc,
class _Ty1,
class _Ty2>
void _Cons_val(_Alloc& _Alval, _Ty1 *_Pdest, _Ty2&& _Src)
{ // construct using allocator
_Alval.construct(_Pdest, _STD forward<_Ty2>(_Src));
}
template<class _Alloc,
class _Ty1>
void _Dest_val(_Alloc& _Alval, _Ty1 *_Pdest)
{ // destroy using allocator
_Alval.destroy(_Pdest);
}
_STD_END
#pragma pop_macro("new")
#pragma warning(pop)
#pragma pack(pop)
#endif /* RC_INVOKED */
#endif /* _XMEMORY_ */
/*
* This file is derived from software bearing the following
* restrictions:
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this
* software and its documentation for any purpose is hereby
* granted without fee, provided that the above copyright notice
* appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation.
* Hewlett-Packard Company makes no representations about the
* suitability of this software for any purpose. It is provided
* "as is" without express or implied warranty.
*/
/*
* Copyright (c) 1992-2009 by P.J. Plauger. ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
V5.20:0009 */
附注:
(1)注意 rebind 结构的使用和作用
(2)Coercion by Member Template 惯用法的使用和作用