C++内存篇(三):allocator——申请未构造内存,根据需要在上面创建对象

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;

<>里也可以是intchardouble......任意你想要的对象类型。

(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);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容