首页 > 编程语言 >【C++11新特性】allocator空间配置类

【C++11新特性】allocator空间配置类

时间:2023-05-14 11:13:59浏览次数:55  
标签:11 ... alloc 对象 C++ 内存 constructor example allocator

原文链接: http://blog.csdn.net/Xiejingfa/article/details/50955295

今天我们来讲讲C++的allocator类。


C++提供了new和delete操作符来管理动态内存空间。new操作通常需要完成两部分工作:一是在系统中申请内存空间,二是在分配的内存上构造对象。delete操作也通常需要完成对应的两部分工作:一个调用相应的析构函数销毁对象,二是回收内存。从这点看,new和delete操作符把内存空间的分配回收与对象的构建销毁紧紧关联在一起。对于new和delete的这种特性,如果我们只是申请单个对象的时候倒是很合适。因为我们几乎可以确定单个对象一定会被使用同时我们也希望将单个对象的内存和初始化组合在一起。

那如果我们需要分配一大块内存呢?这种情形就有点不同。考虑下面这段代码:

#include <iostream>
using namespace std;

class Example
{
public:
    Example() { cout << "example default constructor..." << endl; }
    Example(int x) : a(x) { cout << "example constructor..." << endl; }
    ~Example() { cout << "example destructor..." << endl; }
    int a;
};

int main()
{
    // 如果Example没有默认构造函数,则无法动态分配数组
    Example *p = new Example[10];
    delete[] p;
}

在上面这段代码中,我们new了一个长度为10的Example数组,这时new操作符不仅申请了相应大小的内存空间,还在分别执行了每个元素的默认构造函数。所以它的输出如下:

example default constructor...
example default constructor...
example default constructor...
example default constructor...
example default constructor...
example default constructor...
example default constructor...
example default constructor...
example default constructor...
example default constructor...
example destructor...
example destructor...
example destructor...
example destructor...
example destructor...
example destructor...
example destructor...
example destructor...
example destructor...
example destructor...

如果我们new了长度为10的数组,但并没有全部使用呢?这样剩下那些没有使用的元素就这就产生了额外的对象构造的成本。可见,将内存分配和对象构造结合在一起可能会导致不必要的浪费。而且如果Example中没有默认的构造函数,我们也无法new出动态数组。

有没有一种方法可以将内存的分配回收和对象的构造销毁分离开,让我们在一块内存空间中按需分配对象呢?这就是我们今天要介绍的allocator类。

allocator类是一个模板类,定义在头文件memory中,用于内存的分配、释放、管理,它帮助我们将内存分配和对象构造分离开来。具体地说,allocator类将内存的分配和对象的构造解耦,分别用allocate和construct两个函数完成,同样将内存的释放和对象的析构销毁解耦,分别用deallocate和destroy函数完成。下面我们就来介绍一下这几种函数。

1、内存分配和对象构造

我们可以使用下面语句定义一个名为alloc为类型T分配内存的allocator对象:

allocator<T> alloc;

有了allocator对象后,我们可以使用下面的函数让系统为我们分配一段原始的、未构造的、可以保持n个类型为T的对象的内存空间:

alloc.allocate(n)

与new操作类似,allocate函数调用成功后返回一个指向该段内存第一个元素的指针。allocator分配的对象是未构造的,我们在使用前需要调用construct函数在此内存中构造对象,如果使用为构造的内存,其行为是未定义的。construct的使用方法如下:

alloc.construct(p, args)

p必须是一个类型为T*的指针,指向一块由allocator分配的未构造内存空间。arg为类型T构造函数的参数,用来在p指向的内存空间中构造一个T类型对象。

示例:

#include <iostream>
#include <memory>
using namespace std;

class Example
{
public:
    Example() : a(0) { cout << "example default constructor..." << endl; }
    Example(int x) : a(x) { cout << "example constructor..." << endl; }
    ~Example() { cout << "example destructor..." << endl; }
    int a;
};

int main()
{
    allocator<Example> alloc;
    Example *p = alloc.allocate(2);
    alloc.construct(p);
    alloc.construct(p + 1, 3);
    cout << p->a << endl;
    p++;
    cout << p->a << endl;
}

在上面这段代码中,我们先申请了可以保存两个Example对象的内存空间,然后在第一个位置上调用Example的默认构造函数来构造对象,在第二个位置调用另一个构造函数来构造对象。输出如下:

example default constructor...
example constructor...
0
3

从输出中我们看到,我们只是完成了内存分配和对象构造的工作,构造好的对象并没有析构,内存也没有回收。下面我们来看看如何使用allocator类来完成对象析构和内存回收工作。

2、对象析构和内存回收

当我们使用完对象后,需要对每个构造的对象调用destroy函数来销毁它们。

alloc.destroy(p)

destroy函数接受一个T *的指针,对其指向对象执行构造函数。对象被析构销毁后,分配好的内存空间依然存在,我们可以重新在这块内存上继续构造对象,重复利用,也可以对该内存进行回收操作,归还给系统。内存释放用deallocate函数完成:

alloc.deallocate(p, n)

deallocate函数释放从p开始的长度为n的内存空间,其中p是allocate的返回值,n是该段内存 保存的元素个数,应和allocate的参数n保持一致。需要注意的是,必须由用户来保证调用deallocate前对每个在这块内存中创建的对象调用destroy函数。

示例:

class Example
{
public:
    Example() : a(0) { cout << "example default constructor..." << endl; }
    Example(int x) : a(x) { cout << "example constructor..." << endl; }
    ~Example() { cout << "example destructor..." << endl; }
    int a;
};

int main()
{
    allocator<Example> alloc;
    Example *p = alloc.allocate(2);
    alloc.construct(p);
    alloc.construct(p + 1, 3);
    cout << p->a << endl;
    cout << (p + 1)->a << endl;
    alloc.destroy(p);
    alloc.destroy(p + 1);
    alloc.deallocate(p, 2);

}

输出如下:

example default constructor...
example constructor...
0
3
example destructor...
example destructor...

总结:

  1. allocator类将内存分配回收和对象构造析构分离开来,可以让我们先分配内存再按需构造。
  2. allocator类分配的内存是未构造的,为了使用已经分配好的内存,我们必须使用construct构造对象。如果使用未构造的内存,其行为是未定义的。
  3. 只能对真正构造了的对象进行destroy操作,用户必须保证在调用deallocate函数回收内存前对这块内存上的每个元素调用destroy函数

标签:11,...,alloc,对象,C++,内存,constructor,example,allocator
From: https://www.cnblogs.com/qianqiannian/p/17398915.html

相关文章

  • windows11上安装PL-SQL Developer 15.0.3.2059
    注:连接的oracle服务端是oracle12c1.环境准备(1).下载oracle客户端下载以下版本均可:此处我下载的是instantclient-basic-nt-12.2.0.1.0.zip(2).下载PL-SQLDeveloper15.0.3.2059下载地址:https://www.jb51.net/softs/820654.html2.解压配置oracle客户端首先在磁盘上创建D......
  • 【C++新特性】nullptr关键字
    原文链接:http://blog.csdn.net/xiejingfa/article/details/50478512 熟悉C++的童鞋都知道,为了避免“野指针”(即指针在首次使用之前没有进行初始化)的出现,我们声明一个指针后最好马上对其进行初始化操作。如果暂时不明确该指针指向哪个变量,则需要赋予NULL值。除了NULL之外,C++11新......
  • c++打卡第二十六天
    ①一、问题描述 二、设计思路①、我们可以定义long类型数,算出这个数的平方。②、我们可以判断这个数的位数,然后对平方数除余(数本身位数+1),得到一个余数,判断是否与自身数相等。③、如果相等就打印出来。三、流程图四、代码实现#include<iostream>#include<cmath>using......
  • C++11学习之auto
    原文链接: http://blog.csdn.net/xiejingfa/article/details/50469045 熟悉脚本语言的人都知道,很多脚本语言都引入了“类型自动推断”技术:比如python,可以直接声明变量,在运行时进行类型检查。随着C++11标准的发布,C++语言也引入了类型自动推断的功能,这就是我们今天要介绍的auto关......
  • 2.11 换分币
    问腿:将五元人民币兑换成一元,五角和一角的硬币,共有多少种不同的兑换方式解答流程图程序#include<stdio.h>intmain(){intx,y,z,count=1;printf("可能的兑换方法如下:ln");for(x=0;x<=50;x+=10)/*x为1元硬币钱数,其取值为0,10,20,30,40,50*./for(y=0;y<=50-x;y+=5)......
  • 记一个maven编译打包低级错误"Fatal error compiling: 无效的目标发行版: 11"的解决
    昨天遇到一个java8迁移到java11的项目编译问题,错误如下:[ERROR]Failedtoexecutegoalorg.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile(default-compile)onprojectxxxxx:Fatalerrorcompiling:无效的目标发行版:11->[Help1]初以为是spring或maven......
  • 11种概率分布的拟合与ks检验,可用于概率分析,可靠度计算等领域
    11种概率分布的拟合与ks检验,可用于概率分析,可靠度计算等领域案例中提供11种概率分布,具体包括:gev、logistic、gaussian、tLocationScale、Rayleigh、Loglogistic、Lognormal、GeneralizedPareto、Weibull、Gamma、Exponential等概率分布然后进行ks检验,选择最优概率分布,并画出11中概......
  • c++ class类bfs模板题目
    题目网址:走迷宫-题目-Liuser'sOJ(cpolar.cn)原本代码(bfs广度优先搜索):#include<bits/stdc++.h>usingnamespacestd;constintN=50;intn,m;intsx,sy;chara[N][N];intb[N][N];boolvis[N][N];intdx[]={1,0,-1,0};intdy[]={0,-1,0,1};structnode{i......
  • P1134高精度
    #include<bits/stdc++.h>usingnamespacestd;intmain(){intN;while(cin>>N){inta[3001]={0};inti=0;a[0]=1;while(N){for(i=0;i<3001;i++){......
  • 超微 X11SCA-F 主板 TrueNAS 系统中找不到核显解决办法
    问题表现:执行lspci|grep-ivga显示只有主板集成的ASPEED显示芯片07:00.0VGAcompatiblecontroller:ASPEEDTechnology,Inc.ASPEEDGraphicsFamily(rev41)解决办法:设置BIOS->Advanced->ChipsetConfiguration->SystemAgent(SA)Configuration->Graphic......