当分配一大块内存时,我们通常计划在这块内存上按需构造对象,这样的我们希望将内存分配和对象构造分离。但是通常的new关键字的分配的动态空间,有时候会造成一些浪费,更致命的是“如果一个类没有默认构造函数,那么这个类就不能动态分配数组了”。

这时我们需要一个能将内存分配和对象构造分离的机制,allocator很好地帮助我们解决了这个问题。

#include 《memory》,allocator提供了一种类型感知的内存分配方法,它分配的内存是原始的,未构造的。我们可以利用allocator提供的操作对这些内存进行操作,

allocator<T> a                        定义了一个名为a的allocator对象,它可以为类型为T的对象分配内存
a.allocator(n) 先定义,后分配。这分配一段原始的,未构造的,保存n个类型为T的对象;----》可以看出alllocator方法分配内存,也是先定义类型,在分配类型的数量
a.deallocat(p,n)

note,在此操作之前,必须堆每个在这个内存中创建的对象调用destory方法。

释放从T*,这块内存保存了n类型为T的对象,p必须是一个先前由allocator返回的指针.且n必须是p创建时所要求大小,在调用deallocator之前,用于必须堆每个在这块内存中创建的对象调用destroy方法

a.construct(p,args) p必须是一个T*的指针,指向一个块原始内存,args被传递给类型为T的构造函数,用在在p指向的内存中构造一个对象
a.destroy(p) p为类型为T*的指针,此方法堆p所指对象执行析构函数
  1. allocator<string> alloc;
  2. auto const p = alloc.allcoate(n);
  3.  
  4. auto q = p;
  5. alloc.construct(q++);//*q is a null string
  6. alloc.construct(q++,,'c')// *q is cccccccccc
  7. alloc.construct(q++,"hi")//*q is hi
  8.  
  9. 在未构造对象的情况下,就使用原始内存是错误的
  10. 例如
  11. cout<<*p<<endl;
  12. cout<<*q<<endl;//这个是非法的
  13.  
  14. 记住,为了使用allcocate返回的内存,我们必须用construct构造对象,使用未构造的函数,其行为是未定义的.
  15. 党我们使用完对象后,必须堆每个构造函数调用destroy来销毁
  16. while(q!=p){
  17. alloc.destroy(--q);
  18. }//我们只能堆真正构造了的元素进行destroy操作
  19.  
  20. //一旦元素被销毁后,我们重新使用这部分内存来保存其他string,
    //也可以将内存归还给os,释放内存是通过deallocate(p,n)来完成的
  21.  
  22. alloc.deallocate(p,n);

拷贝/填充未初始化的算法,STL还定义了两个伴随算法,可以在未初始化内存中创建对象

uninitialized_copy(b,e,b2) 从迭代器b和e指出的输入范围拷贝元素到迭代器b2指定的未构造的原始原始内存中,b2指向的内存必须足够大,能容纳输入序列中元素的拷贝
uninitiated_copy(b,n,b2)  
uninitiated_fill(b,e,t)

在迭代器b和e指定的原始内存范围中创建对象,对象的值均为t的拷贝

uninitiated_fill(b,n,t)  
  1. /*
  2. 假定有一个例子,希望将其内容拷贝到动态内存中,我们将分配一块比vector中元素空间大一倍的动态内存,然后将原vector中的元素拷贝到前一半空间,后一半空间利用一个给定值进行填充
  3. */
  4.  
  5. auto p = alloc.allocate(vi.size()*);
  6.  
  7. auto q = uninitiated_copy(vi.begin(),vi.end(),p);
  8.  
  9. uninitiated_fill(q,vi.size(),);

test case

  1. #ifndef STRVEC_H_INCLUDED
  2. #define STRVEC_H_INCLUDED
  3. #include<vector>
  4. #include<string>
  5. #include<memory>
  6. #include<utility>
  7. #include<iostream>
  8. /**
  9. 这里要实现的是一个STLvector的简化版,只能运用于string,由于没有template.
  10. 设计思路:
  11. 1,预先分配足够大的内存来保存可能需要的更多的元素,
  12. 2,当StrVec添加每个元素时,成员函数chk_n_alloc()会检查是否有足够空间容纳更多的元素
  13. 2.1 如果有,alloc.construct()会在下一个可用位置构造一个对象
  14. 2.2 如果没有,StrVec会充分分配空间alloc_n_copy(),并且拷贝一个给定范围中的元素,然后释放掉旧的空间free()
  15. 并添加新的元素
  16.  
  17. ---------------------------------------------
  18. | | | | | |
  19. ---------------------------------------------
  20. ^ ^ ^
  21. elements first_free cap
  22. --
  23. 每个StrVec有三个指针指向其元素所使用的内存:
  24. elements,指向分配中的首元素
  25. frist_free,指向最后一个实际元素位置之后的位置
  26. cap,指向分配的内存末尾之后的位置
  27. ------------------
  28.  
  29. StrVec除了指出位置的指针外,还有名为alloc的静态成员,类型为allocator<string>,它分配我们所需要的内存
  30. ---
  31. 另外还有4个工具函数,
  32. alloc_n_copy(),分配内存并拷贝一个给定范围中的元素
  33. free()//销毁构造的元素病释放内存
  34. chk_n_alloc()//保证StrVec至少能容纳一个新元素的空间,如果没有空间添加新元素,chk_n_alloc会调用reallocate()来分配更多的空间按
  35. reallocate()//在内存使用完后,reallocate()重新分配元素
  36.  
  37. */
  38.  
  39. using namespace std;
  40. class StrVec{
  41. public:
  42. StrVec():elements(nullptr),first_free(nullptr),cap(nullptr){}///构造函数,对成员进行初始化
  43. StrVec(const StrVec&);///拷贝构造函数,从无到有
  44. StrVec &operator=(const StrVec &);///拷贝赋值运算符=,对存在的元素赋予新值
  45. ~StrVec();///析构函数
  46.  
  47. void push_back(const std::string&);///拷贝元素
  48.  
  49. size_t size() const {return first_free - elements;}///返回StrVec中的元素个数
  50. size_t capacity() const {return cap - elements;}///返回StrVec中实际分配的(可以容纳类型元素的)内存大小
  51. string *begin() const {return elements;}///返回首元素
  52. string *end() const {return first_free;}///返回StrVec末尾元素的后一个位置
  53.  
  54. private:
  55. static allocator<string> alloc;///分配元素,注意是静态成员
  56. void chk_n_alloc(){///被添加元素的函数使用
  57. if(size() == capacity())
  58. reallocate();
  59. }///
  60. ///工具函数,被拷贝构造函数,赋值运算符和析构函数使用
  61. pair<string*,string*> alloc_n_copy(const string*,const string*);///什么时候没有空间容纳新元素呢? first_free==cap的时候.
  62. void free();///撤销元素病释放内存
  63. void reallocate();///获得更多内存并且拷贝已有元素
  64.  
  65. string *elements;///指向数组首元素的指针
  66. string *first_free;///指向数组第一个空闲元素的指针
  67. string *cap;///指向数组尾后位置的指针
  68. };
  69.  
  70. void show();
  71.  
  72. #endif // STRVEC_H_INCLUDED

----

  1. #include "StrVec.h"
  2. using namespace std;
  3.  
  4. allocator<string> StrVec::alloc;
  5.  
  6. void show(){
  7. std::cout<<"from StrVec.cpp"<<std::endl;
  8. }
  9.  
  10. void StrVec::push_back(const string& s){
  11. chk_n_alloc();///
  12.  
  13. alloc.construct(first_free++,s);
  14. }
  15.  
  16. ///函数返回一个pair,两个指针分别指向新空间的开始位置和拷贝的尾后位置,即data是新空间开始的位置,uninitiated_copy()返回新空间拷贝的尾后位置
  17. pair<string*, string*>
  18. StrVec::alloc_n_copy(const string *b,const string *e){
  19. auto data = alloc.allocate(e-b);
  20. return make_pair(data,uninitialized_copy(b,e,data));
  21. //return {data,unintialized_copy(b,e,data)};
  22. }
  23.  
  24. void StrVec::free(){
  25. ///can not pass a nullptr to deallocate(),if elements is 0,then free() do nothing
  26. if(elements){
  27. for(auto p = first_free;p != elements;/* */){
  28. StrVec::alloc.destroy(--p);
  29. }
  30. StrVec::alloc.deallocate(elements,cap-elements);
  31. }
  32. }
  33.  
  34. StrVec::StrVec(const StrVec &s){
  35. auto newdata = alloc_n_copy(s.begin(),s.end());
  36. elements = newdata.first;
  37. first_free = newdata.second;
  38. cap = newdata.second;
  39. }
  40.  
  41. StrVec::~StrVec(){
  42. free();
  43. }
  44.  
  45. StrVec &StrVec::operator=(const StrVec &rhs){
  46. ///
  47. auto data = alloc_n_copy(rhs.begin(),rhs.end());
  48. free();///释放掉已有元素之前,调用alloc_n_copy缓存rhs的元素,这可以处理自我赋值
  49. elements = data.first;
  50. first_free = data.second;
  51. cap = data.second;
  52.  
  53. return *this;///
  54. }
  55.  
  56. /**
  57. 在重新分配内存的过程中移动而不是拷贝元素
  58. 我们reallocate()应该做些什么呢?
  59. 1,为一个新的,更大的string数组分配元素
  60. 2,在内存空间的前一部分构造,保存现有元素
  61. 3,销毁原来内存空间中的元素,并释放这块内存
  62. */
  63.  
  64. void StrVec::reallocate(){
  65. auto newcapacity = size() ? *size():;
  66.  
  67. auto newdata = StrVec::alloc.allocate(newcapacity);
  68.  
  69. auto dest = newdata;
  70. auto elem = elements;
  71.  
  72. for(size_t i = ;i != size();i++){
  73. StrVec::alloc.construct(dest++,std::move(*elem++));
  74. }
  75.  
  76. free();
  77.  
  78. elements = newdata;
  79. first_free = dest;
  80. cap = elements + newcapacity;
  81. }

-----main.cpp

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <map>
  5. #include <set>
  6. #include <unordered_set>
  7. #include <unordered_map>
  8. #include "StrVec.h"
  9. using namespace std;
  10.  
  11. int main()
  12. {
  13. show();
  14. StrVec sv;
  15. sv.push_back("aaa");
  16. sv.push_back("bbb");
  17.  
  18. int length = sv.size();
  19. string *ptr = sv.begin();
  20. for(int i = ;i<length;i++){
  21. cout<<*ptr++<<endl;
  22. }
  23.  
  24. StrVec svb(sv);
  25. string *ptrb = svb.begin();
  26. for(int i = ;i<svb.size();i++){
  27. cout<<*ptrb++<<endl;
  28. }
  29.  
  30. StrVec svc = sv;
  31. string *ptrc = svb.begin();
  32. for(int i = ;i<svc.size();i++){
  33. cout<<*ptrc++<<endl;
  34. }
  35. return ;
  36. }

================

allocator class的更多相关文章

  1. 手写一个allocator

    似乎就像是一个计算机原理的实践.. 首先介绍一下大多数操作系统的内存架构..对于某个程序它会认为自己是独占了整个系统的所有内存在运行的这样才能方便移植,因此人们搞出了虚拟内存和物理内存的区别,于是人们 ...

  2. 源码阅读笔记 - 2 std::vector (2) 关于Allocator Aware Container特性

    所有的STL容器,都保存一个或默认,或由用户提供的allocator的实例,用来提供对象内存分配和构造的方法(除了std::array),这样的容器,被称作Allocator Aware Contai ...

  3. STL之分配器allocator

    简单介绍下STL中的分配器allocators. allocators我们一般不会直接接触到,甚至可能并不清楚它的存在,简单的来说,它就是一个幕后工作者,我的印象中它的作用主要在于为容器分配一定的空间 ...

  4. new,delete和malloc,free以及allocator<T>

    一)new和delete,自己觉得一句话就是:最好同一作用域内,必须成对使用 先给出自己的认识: malloc,free,申请和释放一段heap堆中的内存. new:申请heap内存并在申请的内存中放 ...

  5. [转载] 彻底学习STL中的Allocator

    原文: http://cissco.iteye.com/blog/379093 帮助我们理解allocator的原理 Allocator是C++语言标准库中最神秘的部分之一.它们很少被显式使用,标准也 ...

  6. C++ Primer : 第十二章 : 动态内存之allocator类

    标准库allocator类定义在头文件 <memory>中.它帮助我们将内存分配和构造分离开来,它分配的内存是原始的.未构造的. 类似vector,allocator也是一个模板类,我们在 ...

  7. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

  8. [转载]浅析STL allocator

    本文转载自水目沾博客:http://www.cnblogs.com/zhuwbox/p/3699977.html   向大师致敬 一般而言,我们习惯的 C++ 内存配置操作和释放操作是这样的: 1 c ...

  9. allocator例子

    13.39 编写自己的StrVec,包括自己版本的reserve.capacity和resize. 13.40 为StrVec添加一个构造函数,它接受一个initializer_list<str ...

  10. 《STL源码剖析》chapter2空间配置器allocator

    为什么不说allocator是内存配置器而说是空间配置器,因为空间不一定是内存,也可以是磁盘或其他辅助介质.是的,你可以写一个allocator,直接向硬盘取空间.sgi stl提供的配置器,配置的对 ...

随机推荐

  1. Cygwin 下的 自动安装工具 apt-cyg

    类似 于apt-get 或者 yum Cygwin可以在Windows下使用unix环境Bash和各种功能强大的工具,对于Linux管理员来说不想使用Linux桌面是必备的工具. Cygwin下也有类 ...

  2. HDU1430 BFS + 打表 + 康托展开

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1430 , 一道比较好的题. 这道题要用到很多知识,康托展开.BFS.打表的预处理还要用到一一映射,做完 ...

  3. Why malloc+memset is slower than calloc?

    https://stackoverflow.com/questions/2688466/why-mallocmemset-is-slower-than-calloc/ The short versio ...

  4. NOIP2018赛前停课集训记——最后的刷板子计划

    前言 再过两天就\(NOIP2018\)了. 于是,我决定不做其他题目,开始一心一意刷板子了. 这篇博客记录的就是我的刷板子计划. [洛谷3383][模板]线性筛素数 这种普及-的题目我还写挂了两次( ...

  5. 2018.6.29 JavaScript

    一.使用JS数组实现冒泡排序 二.创建Teacher对象,添加(姓名.年龄.地址.学生对象[学生姓名,学生性别])属性 要求: 创建多个老师对象,每个老师下管理多个学生,显示每个老师下所有的学生信息 ...

  6. @TransactionConfiguration过时与替代写法

    在使用了Spring的项目中做单元测试时,以前的标准写法是这样的: 但是在高版本的Spring框架中(Spring4.2以后),@TransactionConfiguration已经标注为过时的注解, ...

  7. Bootstrap历练实例:轮播(carousel)

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  8. webpack4简单入门

    安装webpack需要安装node环境,因此需要在电脑中安装node.node官网https://nodejs.org/,安装LTS版本即可. webpck基本概念 entry:分析依赖模块的入口 o ...

  9. 问题001:Java软件,属于系统软件还是应用软件呢?

    在学习Java前要掌握的一些小问题: 问题一:Java软件,属于系统软件还是应用软件呢? java语言应用在计算机系统上,首先应知道计算机系统分为几部分? 计算机系统由硬件系统和软件系统两部分构成.硬 ...

  10. 理解Express 中间件

    Express 中间件 Express程序基本上是一系列中间件函数的调用.中间件就是一个函数, 接受 req.res.next几个参数. 中间件函数可以执行任何代码, 对请求和响应对象进行修改, 结束 ...