分配器(allocator))是C ++标准库的一个组件, 主要用来处理所有给定容器(vector,list,map等)内存的分配和释放。C ++标准库提供了默认使用的通用分配器std::allocator,但开发者可以自定义分配器。
GNU STL除了提供默认分配器,还提供了__pool_alloc、__mt_alloc、array_allocator、malloc_allocator 内存分配器。
__pool_alloc :SGI内存池分配器
__mt_alloc : 多线程内存池分配器
array_allocator : 全局内存分配,只分配不释放,交给系统来释放
malloc_allocator :堆std::malloc和std::free进行的封装
1、STL allocator简介
new会分配内存并执行对象构造函数,delete会执行对象析构函数并释放内存。如果将内存分配和对象构造分离,可以先分配大块内存,只在需要时才真正执行对象构造函数。
STL在头文件memory中提供了一个allocator类,允许将分配和对象构造分离,提供更好的性能和更灵活的内存管理能力。为了定义一个allocator对象,必须指明allocator可以分配的对象类型。当allocator分配内存时,会根据给定的对象类型来确定恰当的内存大小和对齐位置。
template<typename _Tp>
class allocator : public __allocator_base<_Tp>
{
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<typename _Tp1>
struct rebind
{ typedef allocator<_Tp1> other; };
allocator() throw() { }
allocator(const allocator& __a) throw()
: __allocator_base<_Tp>(__a) { }
template<typename _Tp1>
allocator(const allocator<_Tp1>&) throw() { }
~allocator() throw() { }
// Inherit everything else.
};
根据C++标准规范,STL中分配器的对外接口、成员变量都一样,只是接口内部实现有区别。
allocator实现在模板类new_allocator中:
template<typename _Tp>
class 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;
template<typename _Tp1>
struct rebind
{ typedef new_allocator<_Tp1> other; };
new_allocator() _GLIBCXX_USE_NOEXCEPT { }
new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { }
template<typename _Tp1>
new_allocator(const new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { }
~new_allocator() _GLIBCXX_USE_NOEXCEPT { }
pointer
address(reference __x) const _GLIBCXX_NOEXCEPT
{ return std::__addressof(__x); }
const_pointer
address(const_reference __x) const _GLIBCXX_NOEXCEPT
{ return std::__addressof(__x); }
// NB: __n is permitted to be 0. The C++ standard says nothing
// about what the return value is when __n == 0.
pointer
allocate(size_type __n, const void* = static_cast<const void*>(0))
{
if (__n > this->max_size())
std::__throw_bad_alloc();
return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
}
// __p is not permitted to be a null pointer.
void
deallocate(pointer __p, size_type)
{
::operator delete(__p);
}
size_type
max_size() const _GLIBCXX_USE_NOEXCEPT
{ return size_t(-1) / sizeof(_Tp); }
#if __cplusplus >= 201103L
template<typename _Up, typename... _Args>
void
construct(_Up* __p, _Args&&... __args)
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
template<typename _Up>
void
destroy(_Up* __p) { __p->~_Up(); }
#else
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 402. wrong new expression in [some_] allocator::construct
void
construct(pointer __p, const _Tp& __val)
{ ::new((void *)__p) _Tp(__val); }
void
destroy(pointer __p) { __p->~_Tp(); }
#endif
};
template<typename _Tp>
inline bool
operator==(const new_allocator<_Tp>&, const new_allocator<_Tp>&)
{ return true; }
template<typename _Tp>
inline bool
operator!=(const new_allocator<_Tp>&, const new_allocator<_Tp>&)
{ return false; }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
STL中容器默认分配器为std::allocator<_Tp>,内存分配和释放的接口allocate和deallocate内部实现只是将::operator new和::operator delete进行封装,没用做特殊处理。
3、STL allocator实例
4、自定义allocator
实现Allocator只需要实现allocate和deallocate,来实现自己的内存分配策略。
template<class T >
inline T*_allocate(ptrdiff_t num,T*){
std::cout<<"_allocate"<<endl;
return static_cast<T*>(::operator new(num*sizeof(T)));
}
template <class T>
inline void _deallocate(T* buff){
std::cout<<"_deallocate"<<endl;
::operator delete(buff);
}
template <class T ,class U>
inline void _construct(T* p,const U& value){
new(p)T(value);
}
template<class T>
inline void _destory(T* p){
p->~T();
}
template<typename T>
class MyAlloctor{
public:
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef const T* const_pointer;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
template<typename _Tp1>struct rebind{ typedef MyAlloctor<_Tp1> other; };
MyAlloctor()=default;
~MyAlloctor()=default;
pointer address(reference x){
return static_cast<pointer>(&x);
}
const_pointer address(const_reference x){
return static_cast<const_pointer>(&x);
}
pointer allocate(size_type _n,const void* hit=0 ){
return _allocate(_n,(pointer)0);
}
void deallocate(pointer p,size_type _n){
_deallocate(p);
}
size_type max_size()const throw(){
return static_cast<size_type>(INT_MAX/sizeof(T));
}
void construct(pointer p,const_reference value){
_construct(p,value);
}
void destroy(pointer p){
_destory(p);
}
};
测试代码:
#include
#include
#include
#include
using namespace std;
using namespace __gnu_cxx;//引入new_allocator
class base
{
string name;
int value;
public:
base():name("test"),value(0) { cout << "base ctor" << endl; }
explicit base(int v):name("explicit name"),value(v){cout<<"base ctor value="<<value<<endl;}
virtual ~base() { cout << "base dtor" << endl; }
base(const base& value) { cout << "Copy ctor" << endl; }
base(base&& value) { cout << "move ctor" << endl; }
void who(void){cout<<name<<" value= "<<value<<endl;}
};
int main(void){
new_allocator<base>alloc_test;
new_allocator<base>test;
base* p = alloc_test.allocate(3);
cout<<"test1 start"<<endl;
cout<<"size of base="<<sizeof(base)<<endl;
cout<<"size of *p="<<sizeof(*p)<<endl;
p->who();
//(p+1)->who();
cout<<"test1 end\n"<<endl;
cout<<"test2 start"<<endl;
//test.construct(p,base(1));
//test.construct(p+1,base(2));
//test.construct(p+2,base(3));
alloc_test.construct(p,base(1));
alloc_test.construct(p+1,base(2));
alloc_test.construct(p+2,base(3));
p->who();
(p+1)->who();
(*p).who();
alloc_test.deallocate(p, 3);
getchar();
}
-----------------------------------
// output:
//todo
base dtor //析构对象(仍然占有空间)
test deallocate//删除指针,释放空间。