allocator()类

allocator类

群友之前问了一个问题,C++除了new和malloc还有什么分配内存的方法,当时我在想mmap()、brk()这些系统调用,后来突然想到STL里面有一个allocator类似乎也是做空间分配的。现在来学一学。

new/delete的局限性

抽象的描述new的行为:将内存分配对象构造组合在一起。也就是operator new分配内存,构造函数构造对象。

但有的时候,我们需要将这两个行为分离。比如说,我们先分配一大片内存,然后再内存上构造对象,如果不分离这两个操作,那么我们就会在内存上提前创建大量的对象,但实际上我们不一定需要使用这么多对象。我们期望在我们真正需要时才创建对象。

就像下面这个例子:

string *const p = new string[n];//n个空string
string s;
string *q = p;
while(cin>>s && q != p+n) *q++ = s; //不断输入
const size_t size = q-p;
delete[] p;//销毁

allocator 类

使用时引入#include<memory> 库。

allocator<string> alloc;
auto const p = alloc.allocate(n);

这样我们就可以先分配内存,再逐个创建内存了。

allocator类有这些函数:

//定义一个名为alloc的allocator对象
allocator<T> alloc; 
//分配一段内存,保存n个类型为T的对象,这一段内存是没有构造,返回一个指针指向内存首地址,类型为T*
alloc.allocate(n);
//释放T*指针p开始的地址。这一段内存有n个类型为T的对象
alloc.deallocate(p,n);
//在p指针指向的内存构造一个对象,args是构造函数的参数列表
alloc.construct(p,args);
//析构p指针指向内存的对象,注意在调用deallocate()之前需要调用destory()逐一析构
alloc.destory(p);

拷贝和填充未初始化内存的算法

allocator类还定义了四个算法,可以在未初始化内存中创建内存。

//把迭代器begin和end之间的元素复制给begin2指向的内存
uninitialized_copy(begin,end,begin2);
//把迭代器begin和begin+n之间的元素复制给begin2指向的内存
uninitialized_copy_n(begin,n,tmp);
//把迭代器begin和end之间的元素塞满tmp对象
uninitialized_fill(begin,end,begin2);
//把迭代器begin和begin+n之间的元素塞满tmp对象
uninitialized_fill_n(begin,n,begin2);

repalcement new

如果你想在已经分配的内存中创建一个对象,使用new是不行的。placement new允许你在一个已经分配好的内存中(栈或堆中)构造一个新的对象
replacement new技术实际上就是将一个对象构造在指定的内存区域中。该内存区域可以是静态数据区,栈空间或者是堆空间,对于内存的管理方式不变。

STL的两层配置器

如果你知道malloc的底层原理你就知道,malloc也是两层的处理。通常来说,分配空间小于128k时使用brk()而分配空间大于128k时使用mmap()分配空间。

原因有很多,最经典的就是频繁在堆上开辟空间造成大量外部碎片

STL规定了 __USE_MALLOC 宏,如果它存在则直接调用第一级配置器,不然则直接调用第二级配置器。SGI未定义该宏,也就是说默认使用第二级配置器

_

一级配置器

直接调用malloc和free来配置释放内存

二级配置器

posted @ 2022-08-18 20:20  Paranoid5  阅读(41)  评论(0编辑  收藏  举报