STL源码阅读(1)–allocator配置器
STL的容器都是通过模板实现的,而每个目标的模板类型中会存在一个"typename _Alloc",如vector中的
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >。
这个“typename _Alloc”是什么?意义是什么?
_Alloc是一个allocator类型,用于指定使用那种allocator获取数据存储空间。
vector的template<typename _Tp, typename _Alloc = std::allocator<_Tp> >说明默认指定的allocator是std::allocator。
综上,在阅读容器代码前,我们先了解下allocator的实现。
1. allocator配置器功能
负责空间配置和管理。从实现来看,是一个实现了动态空间配置、空间管理、空间释放的类模板。容器通过allocator配置器来获取数据存储空间。
2. alloctor分类
STL根据不同的应用,C++定制了不同的allocator配置器
/
scoped_allocator
array_allocator
bitmap_allocator:基于cache
debug_allocator:用于debug
extprt_allocator
malloc_allocator:封装malloc和free函数
mt_allocator:多线程相关,基于cache
new_allocator:封装 new和delete
pool_allocator:基于cache
throw_allocator:用于异常
uses_allocator
///
3. alloctor实现
标准allocator
STL的标准接口std::allocator定义在bits/allocator.h文件中,代码为:
template \<typename _Tp\>
class allocator: public __allocator_base<_Tp>
{
}
allocator继承自__allocator_base,在平台相关的头文件x86_64-redhat-linux\bits\c++allocator.h中有如下定义:
#if __cplusplus >= 201103L
namespace std
{
template<typename _Tp>
using __allocator_base = __gnu_cxx::new_allocator<_Tp>;
}
#else
#define __allocator_base __gnu_cxx::new_allocator
#endif
因此,标准的allocator实际是new_allocator。根据C++标准,STL的allocator,把对象的申请和释放分成4步:
1、申请内存空间
2、执行构造函数
3、执行析构函数
4、释放内存空间
在ext/new_allocator.h中对应封装了4个接口:
allocate()
construct()
destroy()
deallocate()
pointer allocate(size_type __n, const void* = 0)
{
if (__n > this->max_size())
std::__throw_bad_alloc();
return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
}
void deallocate(pointer __p, size_type)
{ ::operator delete(__p); }
#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
void construct(pointer __p, const _Tp& __val)
{ ::new((void *)__p) _Tp(__val); }
void
destroy(pointer __p) { __p->~_Tp(); }
#endif
从代码来看:
allocate()通过封装全局的operator new来分配内存。
deallocate()通过封装全局的operator delete来释放内存。
construct()通过封装全局的placement new来构造对象。
destroy()通过调用析构函数析构对象。
其他的allocator的实现大体类似。