关于STL allocator

来源:互联网 发布:淘宝店铺装修页尾在线 编辑:程序博客网 时间:2024/06/06 10:57

关于STL 中allocator的接口与实现,C++标准有比较清楚的定义:allocator wiki


1. SGI STL版本的allocator并没有遵守C++标准。它只提供simple_alloc类共container使用,设计的allocator名字叫做alloc,有二级配置器。第一级配置采用malloc/free来实现allocate/deallocate,第二级配置器采用针对申请的内存有特别处理,如果大小大于128字节,则转调用第一级配置来分配和释放内存,否则采用memory pool的方式来分配这些小额的内存。在SGI STL中,默认采用第二级内存分配器。具体的可以阅读侯捷的《STL源码剖析》第二章。
在SGI STL 3.3中,已经提供了一个符合C++标准的allocator接口,通过对内部的alloc转调用来实现。

a)
b)
c)
d)
e)


2. GNU C++的STL内部借鉴SGI STL的实现,不过它对外的的STL allocator严格遵守C++的标准:


看一下它的代码:(定义在bits/allocator.h文件中)
namespace std{templateclass allocator;template<>class allocator{public:typedef size_t size_type;typedef ptrdiff_t difference_type;typedef void* pointer;typedef const void* const_pointer;typedef void value_type;templatestruct rebind{ typedef allocator other; };};/*** @brief The "standard" allocator, as per [20.4].** (See @link Allocators allocators info @endlink for more.)*/templateclass allocator: public ___glibcxx_base_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;templatestruct rebind{ typedef allocator other; };allocator() throw() { }allocator(const allocator& a) throw(): ___glibcxx_base_allocator(a) { }templateallocator(const allocator&) throw() { }~allocator() throw() { }// Inherit everything else.};templateinline booloperator==(const allocator&, const allocator&){ return true; }templateinline booloperator!=(const allocator&, const allocator&){ return false; }// Inhibit implicit instantiations for required instantiations,// which are defined via explicit instantiations elsewhere.// NB: This syntax is a GNU extension.#if _GLIBCXX_EXTERN_TEMPLATEextern template class allocator;extern template class allocator;#endif// Undefine.#undef ___glibcxx_base_allocator} // namespace std

template 类___glibcxx_base_allocator 定义在具体的平台相关的头文件中,例如i386-redhat-linux/bits/c++allocator.h:
// Define new_allocator as the base class to std::allocator.#include <ext/new_allocator.h>#define ___glibcxx_base_allocator __gnu_cxx::new_allocator</code>


根据GCC/libstdc++的DOC, 知道
The current default choice for allocator is __gnu_cxx::new_allocator.
可以看出GNU c++的allocator其实采用的是new/delete-based allocation.
namespace __gnu_cxx{/*** @brief An allocator that uses global new, as per [20.4].** This is precisely the allocator defined in the C++ Standard.* - all allocation calls operator new* - all deallocation calls operator delete** (See @link Allocators allocators info @endlink for more.)*/templateclass new_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;templatestruct rebind{ typedef new_allocator other; };new_allocator() throw() { }new_allocator(const new_allocator&) throw() { }templatenew_allocator(const new_allocator&) throw() { }~new_allocator() throw() { }pointeraddress(reference __x) const { return &__x; }const_pointeraddress(const_reference __x) const { return &__x; }// NB: __n is permitted to be 0. The C++ standard says nothing// about what the return value is when __n == 0.pointerallocate(size_type __n, const void* = 0){ return static_cast(::operator new(__n * sizeof(_Tp))); }// __p is not permitted to be a null pointer.voiddeallocate(pointer __p, size_type){ ::operator delete(__p); }size_typemax_size() const throw(){ return size_t(-1) / sizeof(_Tp); }// _GLIBCXX_RESOLVE_LIB_DEFECTS// 402. wrong new expression in [some_] allocator::constructvoidconstruct(pointer __p, const _Tp& __val){ ::new(__p) _Tp(__val); }voiddestroy(pointer __p) { __p->~_Tp(); }};templateinline booloperator==(const new_allocator&, const new_allocator&){ return true; }templateinline booloperator!=(const new_allocator&, const new_allocator&){ return false; }} // namespace __gnu_cxx


不过GNU GCC提供了更多很有意思的定制allocator: __gnu_cxx::malloc_allocator(malloc_allocator.h)</em>, __gnu_cxx::bitmap_allocator (bitmap_allocator.h), __gnu_cxx::pool_allocator(pool_allocator.h), and __gnu_cxx::__mt_alloc(mt_allocator.h)


可通过--enable-libstdcxx-allocator 选项来开启其它的allocator,或者在定义一个container时,显式的描述模板参数表示用哪一个allocator:

#include <ext/malloc_allocator.h>std::vector<int, __gnu_cxx::malloc_allocator<int> > malloc_vector;




3. MSVC的STL采用了P.J. Plauger的版本:allocator类定义在了include/xmemory文件中(以VS2008为例):
// TEMPLATE FUNCTION _Allocatetemplate<class _Ty> inline_Ty _FARQ *_Allocate(_SIZT _Count, _Ty _FARQ *){ // check for integer overflowif (_Count <= 0)_Count = 0;else if (((_SIZT)(-1) / _Count) < sizeof (_Ty))_THROW_NCEE(std::bad_alloc, NULL);// allocate storage for _Count elements of type _Tyreturn ((_Ty _FARQ *)::operator new(_Count * sizeof (_Ty)));}// TEMPLATE FUNCTION _Constructtemplate<class _T1,class _T2> inlinevoid _Construct(_T1 _FARQ *_Ptr, const _T2& _Val){ // construct object at _Ptr with value _Valvoid _FARQ *_Vptr = _Ptr;::new (_Vptr) _T1(_Val);}// TEMPLATE FUNCTION _Destroytemplate inlinevoid _Destroy(_Ty _FARQ *_Ptr){ // destroy object at _Ptr_DESTRUCTOR(_Ty, _Ptr);}template <> inlinevoid _Destroy(char _FARQ *){ // destroy a char (do nothing)}template <> inlinevoid _Destroy(wchar_t _FARQ *){ // destroy a wchar_t (do nothing)}

它的_Allocate模板函数直接采用全局的operator new来分配内存。
// TEMPLATE CLASS _Allocator_basetemplatestruct _Allocator_base{ // base class for generic allocatorstypedef _Ty value_type;};// TEMPLATE CLASS _Allocator_basetemplatestruct _Allocator_base{ // base class for generic allocators for const _Tytypedef _Ty value_type;};// TEMPLATE CLASS allocatortemplateclass allocator: public _Allocator_base{ // generic allocator for objects of class _Typublic:typedef _Allocator_base _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;templatestruct rebind{ // convert an allocator to an allocatortypedef allocator other;};pointer address(reference _Val) const{ // return address of mutable _Valreturn (&_Val);}const_pointer address(const_reference _Val) const{ // return address of nonmutable _Valreturn (&_Val);}allocator() _THROW0(){ // construct default allocator (do nothing)}allocator(const allocator&) _THROW0(){ // construct by copying (do nothing)}templateallocator(const allocator&) _THROW0(){ // construct from a related allocator (do nothing)}templateallocator& operator=(const allocator&){ // 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 elementsreturn (_Allocate(_Count, (pointer)0));}pointer allocate(size_type _Count, const void _FARQ *){ // allocate array of _Count elements, ignore hintreturn (allocate(_Count));}void construct(pointer _Ptr, const _Ty& _Val){ // construct object at _Ptr with value _Val_Construct(_Ptr, _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);}};// allocator TEMPLATE OPERATORStemplate inlinebool operator==(const allocator&, const allocator&) _THROW0(){ // test for allocator equality (always true)return (true);}template inlinebool operator!=(const allocator&, const allocator&) _THROW0(){ // test for allocator inequality (always false)return (false);}// CLASS allocatortemplate<> class _CRTIMP2_PURE allocator{ // generic allocator for type voidpublic:typedef void _Ty;typedef _Ty _FARQ *pointer;typedef const _Ty _FARQ *const_pointer;typedef _Ty value_type;templatestruct rebind{ // convert an allocator to an allocatortypedef allocator other;};allocator() _THROW0(){ // construct default allocator (do nothing)}allocator(const allocator&) _THROW0(){ // construct by copying (do nothing)}templateallocator(const allocator&) _THROW0(){ // construct from related allocator (do nothing)}templateallocator& operator=(const allocator&){ // assign from a related allocator (do nothing)return (*this);}};



原创粉丝点击