引言:

  • 在介绍allocator之前,先看一下下面的案例
  • new表达式分配了50个string。但是我们可能没有使用到50个string。但是那些没有被使用到的string也被初始化了并且申请了内存空间,这样就造成了内存的浪费 
string *const p = new string[50];
string s;
string *q = p;

while (cin >> s && q != p + n) //输入stirng
    *q++ = s;
delete[] p;//释放p指向的数组
一、allocator类简介
  • 头文件
  • 标准库allocator类帮助我们将内存分配和对象构造分离开来。它分配的内存是原始的、未构造的

C++:35---动态内存allocator类_内存空间

  • a.address(x); //返回某个对象的地址,等同于&x
  • a.max_size();//返回可成功配置的最大量

C++:35---动态内存allocator类_内存空间_02

二、allocator类的使用

使用方法:

  • 第一步:使用allocator<>模板定义一个特定类型的allocator类对象
  • 第二步:使用allocate()函数分配一块指定大小的内存,该内存中的对象都是未构造的
  • 第三步:使用construct()函数对指定位置的元素就行初始化
  • 第四步:如果某个位置的元素不想使用就调用destroy()函数来销毁它们(但是空间还没有释放)。如果该位置需要重新使用就调用allocate()函数来初始化。如果不再使用进行下一步
  • 第五步(依情况而选):元素销毁之后,可以调用deallocate()函数来释放内存
三、allocate函数
  • 功能:allocator模板定义出来的类对象并没有分配内存空间,只是定义了一个对象。此后需要调用allocate()函数来指定分配的元素个数
  • 特点:allocate()函数分配的元素都是未初始化的,因此不能够直接使用。后面会介绍使用construct()函数来初始化
  • 返回值:返回allocator类对象的首元素地址
allocator<string> alloc;  //可以分配string的allocator对象,此时还不占用内存空间
auto const p = alloc.allocate(10); //分配n个未初始化的string
四、construct函数
  • 功能:allocate()函数分配的内存元素都是未初始化的,因此不能够直接使用,需要调用该函数来对指定位置的元素进行初始化
  • 特点:参数1位一个地址,参数2以及之后的参数是可变的(用来对参数1指定的位置进行初始化的元素)
allocator<string> alloc;
auto const p = alloc.allocate(10); 
auto q=p; //q指向最后构造的元素之后的位置

//在q位置进行构造,然后指针再向后偏移一个元素的大小
alloc.construct(q++);       //*q为空字符串
alloc.construct(q++,10,'c');//*q为10个c的字符串(cccccccccc)
alloc.construct(q++,"hi");  //*q为hi

还未构造对象就直接使用是错误的:

cout<< *p <<endl;  //正确,使用stirng的输出运算符
cout<< *q <<endl;  //错误,q最后++指向一块未构造的内存
五、destroy函数
  • 功能:当我们使用完对象之后,如果不再需要该对象,就可以调用该函数来销毁指定的元素
  • 参数:为一个指定位置元素的地址
  • 在循环开始处,q指向最后一个构造的元素的下一个位置,我们将其传入destroy函数中,然后循环递减逐渐释放内存 
while(q!=p)
    alloc.destroy(--q);  //销毁指定位置的元素
六、deallocate函数
  • 功能:如果destroy函数销毁指定位置的元素之后,该位置不再使用,就可以调用该函数来释放该位置的内存空间
  • 参数:参数1是要销毁的内存起始地址,参数2是要销毁的个数
  • 注意:参数1的指针不能为空
  • 上面我们调用了destroy函数销毁了所有的元素,接下来我们调用deallocate函数将所有的元素内存释放 
alloc.deallocate(p,10);
七、拷贝和填充未初始化内存的算法
  • 标准库为allocator类定义了两个伴随算法。可以在未初始化内存中创建对象
  • 头文件:#include<memory>

C++:35---动态内存allocator类_动态内存_03

uninitialized_copy函数返回递增后的目的位置迭代器

演示案例:

  • 我们现在有一个int型的vector。然后我们创建一个2倍vector对象的动态内存,然后在动态内存的前半部分拷贝vector的对象。后半部分用指定的值填充
vector<int> vi = { 1,2,3,4,5 };      //分配一个vector数组
allocator<int> alloc;
auto p=alloc.allocate(vi.size() * 2);//分配一个2倍vector大小的动态内存

auto q = uninitialized_copy(vi.begin(), vi.end(), p); //动态内存前半部分拷贝vector的内存,uninitialized_copy函数返回递增后的目的位置迭代器(alloc中间位置的地址)
uninitialized_fill_n(q,vi.size(),666);  //动态内存后半部分,全部使用666数组初始化