allocator类
一、allocator是干嘛的
我们知道用new可以来进行动态大小的内存分配,在分配内存的同时new也会完成构造对象这个过程。
在分配单个我们知道要什么值的对象的内存时,这很方便。
然而如果我想要一大块内存——比如说我可能要存放几千个对象,于是我先去申请一万个对象的内存,我现在不知道我要取一万个什么值,也不知道具体最后会用多少个对象。这时我如果用new的话,会对所有申请的内存创建对象并赋予他们一些没有用的初始值,那些最后没有用到的内存白白浪费了很多个创建对象操作,后来用到的对象值被修改的内存也白白浪费了很多个赋值操作。
而且更重要的是,有一些类没有默认构造函数,这样它们是不能用new来动态分配数组的。
这时候我希望先给我一大块内存而不要做别的,等我需要时再去上面创建对象和初始化。完成这种功能的东西就是allocator。
二、怎么用allocator类
1.include<memory>
首先allocator类放在头文件memory中,于是你要先include它:
#include<memory>
2.分配内存,在上面构造对象
涉及三个关键字:
-
allocator:声明一个内存分配器 -
allocate:分配内存 -
construct:在内存上构造对象
(1)allocator:内存分配器
现在我想要一个为我分配string类型的内存的allocator,我称它为AS:
allocator<string> AS;
<>里也可以是int,char,double......任意你想要的对象类型。
(2)allocate:分配内存
现在我想要申请一万个string的内存空间:
string* const p = AS.allocate(10000);
我用allocate(10000)让AS为我分配还没有构造的(unconstructed)能放10000个string的连续内存,AS完成了这个工作,并且返回一个指向这一块内存的首地址给指针p。我希望p记住这个首地址在哪免得我后边找不到了,所以我把它设为const的。
(3)construct:创建对象
下面我让AS为我在这些内存上构造对象:AS.construct(内存地址,参数......),括号里的“参数”是给我这块内存的对象类型的构造函数的参数,比如这里对于string,可以这样:
string* q = p; //q现在是该块内存的首地址
AS.construct(q,10,'a');
q++; //把地址q往后挪一位到下一个未构造的内存地址
这里我把参数10和'a'传给string的构造函数,所以我在首地址上构造了一个内容为"aaaaaaaaaa"的string。
也可以是其他的构造方法:
AS.construct(q,"我的string");
q++
AS.construct(q);
q++
这样一来,我分别在我申请的内存上的第0个、第1个、第2个地址上构造出了"aaaaaaaaaa"、"我的string"、""。
3.销毁对象和归还内存
涉及两个关键字:
-
destroy:销毁对象,释放对象所在的内存空间 -
deallocate:归还申请的内存
(1)destroy:销毁一个已构造的对象
当我们用完对象后,对于每个构造出来的元素都要用destroy(内存地址)来销毁它:
while(q!=p){
q--;
AS.destroy(q); //释放内存地址q指向的内存空间
}
元素销毁后,它所在的内存回到未构造状态,我们可以把它们拿来构造新的对象。
(2)deallocate:归还申请的内存
归还内存前我们必须把在上面的所有对象destroy掉,然后我之前申请了10000块内存,现在归还的数量也必须还是10000:
AS.deallocate(p,10000);
deallocate接受两个参数,第一个是之前我们保存的申请的这块内存的首地址,第二个是归还的数量。注意归还时给出的首地址和内存块数量必须和申请时一模一样,否则可能会造成内存泄漏噢。
三、allocator使用方法总结表格
| 函数 & 用法 | 功能 |
|---|---|
allocator<T> AT |
定义一个内存分配器AT,分配内存类型为T类 |
T* const p=AT.allocate(n) |
让AT为你分配一块大小为n个T类对象大小的未构造内存空间,返回其首地址给p |
AT.construct(q,参数) |
在该块内存上的地址q上,通过传送参数给T类的构造函数来构造一个对象 |
AT.destroy(q) |
销毁在该块内存上的地址q上已创建的对象 |
AT,deallocate(p,n) |
归还之前申请的内存。p为申请的内存块首地址,n为申请的内存块个数,两者都必须和申请时的一致。 |
四、代码
#include<iostream>
#include<memory>
using namespace std;
int main() {
//定义分配器AS并用它申请10000块string型内存
allocator<string> AS;
string* const p = AS.allocate(10000);
string* q = p; //令q为该块内存的首地址
//在内存块上构造对象
AS.construct(q, 10, 'a'); //在地址q上构造一个string“aaaaaaaaaa”
q++; //把地址q往后挪一位到下一个未构造的内存地址
AS.construct(q, "我的string"); //在地址q上构造一个string“我的string”
q++; //把地址q往后挪一位到下一个未构造的内存地址
AS.construct(q); //在地址q上构造一个空string
q++; //把地址q往后挪一位到下一个未构造的内存地址
//销毁已构造的对象
while (q != p) {
q--;
AS.destroy(q); //释放内存地址q指向的内存空间
}
//归还申请的10000块string型内存
AS.deallocate(p, 10000);
}