STL定义了两种空间配置器:
- allocator:位于<defalloc.h>
- alloc:在<memory>包含以下头文件,将功能分离:
-
- 全局函数construct()/destroy():位于<stl_construct.h>,用于构造/析构对象。
- 配置器alloc:位于<stl_alloc.h>,用于空间配置,分为一级配置器和二级配置器。
- uninitialized_copy/uninitialized_fill/uninitialized_fill_n:位于<stl_uninitialized.h>,用于填充或复制大块数据。
allocator配置器在分配空间时使用标准库函数operator new/operator delete。处于效率考虑,STL没有使用这个allocator,而是使用了更为精细的alloc配置器,将空间管理和对象管理两个阶段分离开来。
这样是为了解决内存碎片问题,TSL的空间配置器分两级。当申请空间大于128bytes时,使用第一级配置器;当申请空间小于128bytes时,使用第二级配置器。
- 第一级:__malloc_alloc_template,直接使用malloc、realloc、free管理内存。
- 第二级:__default_alloc_template,采用memory pool,由free-list维护。总共有16个free-list,每个free-list串联了一个个的内存块,当申请内存时就从一个适当的free-list中拔出一个区块给用户,用完后在返还给free-list。
两个空间配置器都是通过标准接口allocate()、deallocate()进入空间分配和空间释放的过程的。
无论alloc被定义为第一级或第二级配置器,SGI还为它再包装一个接口simple_alloc,每一个容器都直接包含这个类,当需要配置空间时,再由此类转调用allocate或deallocate:
~~~
template<class T, class Alloc>
class simple_alloc { // 对配置器alloc再进行一次封装,容器就使用这个类进行空间管理
public:
static T *allocate(size_t n)
{ return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); }
static T *allocate(void)
{ return (T*) Alloc::allocate(sizeof (T)); }
static void deallocate(T *p, size_t n)
{ if (0 != n) Alloc::deallocate(p, n * sizeof (T)); }
static void deallocate(T *p)
{ Alloc::deallocate(p, sizeof (T)); }
};
~~~
容器内部直接使用这个类分配空间,例如在vector中:
~~~
typedef T value_type;
typedef simple_alloc<value_type, Alloc> data_allocator;
~~~
注意只是定义了空间分配器的类型,并没有定义实际对象。
当要分配或删除节点时:
~~~
iterator new_start = data_allocator::allocate(len); // 分配元素空间
data_allocator::deallocate(new_start, len); // 删除元素空间
~~~
利用类型限定符进行空间分配和释放。
参考:
《STL源码剖析》第二章。
- 前言
- 顺序容器 — heap
- 关联容器 — 红黑树
- 关联容器 — set
- 关联容器 — map
- 关联容器 — hashtable
- 关联容器 — hash_set
- 关联容器 — hash_map
- 算法 — copy
- 顺序容器 — stack
- 顺序容器 — queue
- 顺序容器 — priority_queue
- 顺序容器 — slist
- construct()和destroy()
- 空间配置器
- 函数适配器
- 迭代器以及“特性萃取机”iterator_traits
- 算法 — partial_sort
- 算法 — sort
- 仿函数
- 适配器(adapters)
- C++简易vector
- C++简易list
- STL算法实现
- C++模板Queue