目录
对于一些容器如vector、map、set之类的,都需要一个模板参数Alloc,用来指定一个空间配置器,这个配置器的作用,就是管理内存的分配和释放。在SGI STL中,提供了默认的配置器,这也是为什么我们在创建一个vector、map的时候不需要传入第二个参数。以vector为例,其头部定义如下:
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class vector : protected _Vector_base<_Tp, _Alloc>
{...}
这里指定了一个默认的配置器参数, __STL_DEFAULT_ALLOCATOR(_Tp)。 这是一个宏,它有两种情况:
# ifndef __STL_DEFAULT_ALLOCATOR
# ifdef __STL_USE_STD_ALLOCATORS
# define __STL_DEFAULT_ALLOCATOR(T) allocator< T >
# else
# define __STL_DEFAULT_ALLOCATOR(T) alloc
# endif
# endif
也就是说,默认的配置器要么是allocator,要么就是alloc。
allocator
当然这里的allocator并不是本文的重点,因为它只是把operator new和operator delete简单进行了封装,如下所示:
template <class T>
inline T* allocate(ptrdiff_t size, T*) {//进行内存的分配,并且返回分配内存的首地址
set_new_handler(0);
T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
if (tmp == 0) {
cerr << "out of memory" << endl;
exit(1);
}
return tmp;
}
template <class T>
inline void deallocate(T* buffer) {//delete释放资源
::operator delete(buffer);
}
template <class T>
class allocator {
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
pointer allocate(size_type n) {
return ::allocate((difference_type)n, (pointer)0);
}
void deallocate(pointer p) { ::deallocate(p); }
pointer address(reference x) { return (pointer)&x; }
const_pointer const_address(const_reference x) {
return (const_pointer)&x;
}
size_type init_page_size() {
return max(size_type(1), size_type(4096/sizeof(T)));
}
size_type max_size() const {
return max(size_type(1), size_type(UINT_MAX/sizeof(T)));
}
};
allocator的内容很简单,下面着重来看看alloc。
alloc
alloc是一个经过typedef定义的新类型,其定义如下:
typedef __malloc_alloc_template<0> malloc_alloc;
# ifdef __USE_MALLOC
typedef malloc_alloc alloc;
...
#else typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;
...
#endif
从这里可以看到,alloc的类型实际上是由__USE_MALLOC这个宏来定义的,如果定义了,那么alloc使用的就是__malloc_alloc_template,否则就是__default_alloc_template。
这两个都是类,前者就是一级配置器,后者是二级配置器。二者都包含了基本的内存分配、内存释放等函数。
一级配置器
一级配置器是__malloc_alloc_template类,其定义如下:
template <int __inst>
class __malloc_alloc_template {
private:
static void* _S_oom_malloc(size_t);
static void* _S_oom_realloc(void*, size_t);
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
static void (* __malloc_alloc_oom_handler)();
#endif
public:
static void* allocate(size_t __n)
{
void* __result = malloc(__n); //直接用malloc进行分配,如果分配失败调用_S_oom_mallo
if (0 == __result) __result = _S_oom_malloc(__n);
return __result;
}
static void deallocate(void* __p, size_t /* __n */)
{
free(__p); //释放
}
static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz)
{
void* __result = realloc(__p, __new_sz); //用realloc分配,分配失败调用_S_oom_realloc
if (0 == __result) __result = _S_oom_realloc(__p, __new_sz);
return __result;
}
static void (* __set_malloc_handler(void (*__f)()))()//设置异常捕捉函数,并且返回设之前老的捕捉函数
{
void (* __old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = __f;
return(__old);
}
};
一级配置器其实很简单,它内部的allocate、deallocate和reallocate函数实际上就是对malloc、free和realloc的简单封装,还提供了一个设置异常捕捉函数的接口__set_malloc_handler,这个函数的作用就是用传入的函数指针更新类静态变量函数指针__malloc_alloc_oom_handler并且返回更新前的__malloc_alloc_oom_handler。
那么__malloc_alloc_oom_handler这个函数指针有什么用呢?
在allocate和reallocate函数中,如果内存分配失败,就会调用相应的_S_oom_alloc和_S_oom_realloc,它们的定义如下:
template <int __inst>
void*
__malloc_alloc_template<__inst>::_S_oom_malloc(size_t __n)
{
void (* __my_malloc_handler)();
void* __result;
for (;;) {//循环调用malloc,直到分配成功,分配失败就调用异常捕捉函数
__my_malloc_handler = __malloc_alloc_oom_handler;
if (0 == __my_malloc_handler) { __THROW_