在STL中,空间配置器是容器必不可少的东西,它为容器中的数据提供空间存储,由于考虑小型区块可能造成的内存碎片问题,STL中设计了双层级配置器,当开辟内存>128bytes时,就会调用第一级配置器,在这里我们将根据其源码模拟实现它的第一级配置器。
STL 第一级配置器
代码实现:
#pragma once
//一级空间配置器
#define __THROW_BAD_ALLOC 0
template <int inst>
class __MallocAllocTemplate
{
public:
static void * Allocate(size_t n)
{
void* result=malloc(n);
if(result==0)
{
//若开辟失败调用__Oom_Malloc函数
result=__Oom_Malloc(n);
}
return result;
}
static void Deallocate(void *p)
{
free(p);//直接调用free
}
static void * Reallocate(void *p, size_t new_sz)
{
void* result=realloc(p,new_sz);
if(result==0)
{
result=__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);
}
private:
static void (* __Malloc_Alloc_Oom_Handler)();
//处理内存不足情况
static void *__Oom_Malloc(size_t n)
{
void (*My_Malloc_Handler)();
void* result;
while(1)//***用户需小心使用自己定义的处理函数,否则会使程序陷入死循环
{
My_Malloc_Handler=__Malloc_Alloc_Oom_Handler;//用户自己的处理函数地址
if(My_Malloc_Handler==0)
{
throw __THROW_BAD_ALLOC;
}
(*My_Malloc_Handler)();//调用处理函数,释放内存
result=malloc(n);//再次开辟内存
if(result)
return result;
}
}
static void *__Oom_Realloc(void *p, size_t n)
{
void(*My_Malloc_Handler)();
void* result;
while(1)
{
My_Malloc_Handler=__Malloc_Alloc_Oom_Handler;
if(My_Malloc_Handler==0)
{
throw __THROW_BAD_ALLOC;
}
(*My_Malloc_Handler)();
result=realloc(p,n);
if(result)
return result;
}
}
};
template <int inst>
void (* __MallocAllocTemplate<inst>::__Malloc_Alloc_Oom_Handler)() = 0;//默认为0
typedef __MallocAllocTemplate<0> malloc_alloc;
void Test()
{
int* pa=(int*)malloc_alloc::Allocate(sizeof(int)*5);
for(size_t i=0;i<5;++i)
{
pa[i]=i;
}
pa=(int*)malloc_alloc::Reallocate(pa,sizeof(int)*8);
for(size_t i=5;i<8;++i)
{
pa[i]=i*10;
}
malloc_alloc::Deallocate(pa);
}
以上实现中简单测试了结果。
由上代码可知:第一级配置器以malloc()、free()、realloc()等C函数执行实际的内存配置、释放等操作,并实现模拟了C++new-handler机制,即当系统无法开辟内存时调用一个用户指定的处理机制,当用户设定时,它则会不断调用处理机制函数,直到获得内存成功返回,所以客户在指定时要小心使用,以防程序陷入死循环崩溃;但如果用户没有设定,由上程序可知__Malloc_Alloc_Oom_Handler() = 0默认为0,即处理内存不足的函数直接抛出异常。