当分配一大块内存时,我们通常计划在这块内存上按需构造对象,这样的我们希望将内存分配和对象构造分离。但是通常的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所指对象执行析构函数
allocator<string> alloc;
auto const p = alloc.allcoate(n); auto q = p;
alloc.construct(q++);//*q is a null string
alloc.construct(q++,,'c')// *q is cccccccccc
alloc.construct(q++,"hi")//*q is hi 在未构造对象的情况下,就使用原始内存是错误的
例如
cout<<*p<<endl;
cout<<*q<<endl;//这个是非法的 记住,为了使用allcocate返回的内存,我们必须用construct构造对象,使用未构造的函数,其行为是未定义的.
党我们使用完对象后,必须堆每个构造函数调用destroy来销毁
while(q!=p){
alloc.destroy(--q);
}//我们只能堆真正构造了的元素进行destroy操作 //一旦元素被销毁后,我们重新使用这部分内存来保存其他string,
//也可以将内存归还给os,释放内存是通过deallocate(p,n)来完成的 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)  
/*
假定有一个例子,希望将其内容拷贝到动态内存中,我们将分配一块比vector中元素空间大一倍的动态内存,然后将原vector中的元素拷贝到前一半空间,后一半空间利用一个给定值进行填充
*/ auto p = alloc.allocate(vi.size()*); auto q = uninitiated_copy(vi.begin(),vi.end(),p); uninitiated_fill(q,vi.size(),);

test case

 #ifndef STRVEC_H_INCLUDED
#define STRVEC_H_INCLUDED
#include<vector>
#include<string>
#include<memory>
#include<utility>
#include<iostream>
/**
这里要实现的是一个STLvector的简化版,只能运用于string,由于没有template.
设计思路:
1,预先分配足够大的内存来保存可能需要的更多的元素,
2,当StrVec添加每个元素时,成员函数chk_n_alloc()会检查是否有足够空间容纳更多的元素
2.1 如果有,alloc.construct()会在下一个可用位置构造一个对象
2.2 如果没有,StrVec会充分分配空间alloc_n_copy(),并且拷贝一个给定范围中的元素,然后释放掉旧的空间free()
并添加新的元素 ---------------------------------------------
| | | | | |
---------------------------------------------
^ ^ ^
elements first_free cap
--
每个StrVec有三个指针指向其元素所使用的内存:
elements,指向分配中的首元素
frist_free,指向最后一个实际元素位置之后的位置
cap,指向分配的内存末尾之后的位置
------------------ StrVec除了指出位置的指针外,还有名为alloc的静态成员,类型为allocator<string>,它分配我们所需要的内存
---
另外还有4个工具函数,
alloc_n_copy(),分配内存并拷贝一个给定范围中的元素
free()//销毁构造的元素病释放内存
chk_n_alloc()//保证StrVec至少能容纳一个新元素的空间,如果没有空间添加新元素,chk_n_alloc会调用reallocate()来分配更多的空间按
reallocate()//在内存使用完后,reallocate()重新分配元素 */ using namespace std;
class StrVec{
public:
StrVec():elements(nullptr),first_free(nullptr),cap(nullptr){}///构造函数,对成员进行初始化
StrVec(const StrVec&);///拷贝构造函数,从无到有
StrVec &operator=(const StrVec &);///拷贝赋值运算符=,对存在的元素赋予新值
~StrVec();///析构函数 void push_back(const std::string&);///拷贝元素 size_t size() const {return first_free - elements;}///返回StrVec中的元素个数
size_t capacity() const {return cap - elements;}///返回StrVec中实际分配的(可以容纳类型元素的)内存大小
string *begin() const {return elements;}///返回首元素
string *end() const {return first_free;}///返回StrVec末尾元素的后一个位置 private:
static allocator<string> alloc;///分配元素,注意是静态成员
void chk_n_alloc(){///被添加元素的函数使用
if(size() == capacity())
reallocate();
}///
///工具函数,被拷贝构造函数,赋值运算符和析构函数使用
pair<string*,string*> alloc_n_copy(const string*,const string*);///什么时候没有空间容纳新元素呢? first_free==cap的时候.
void free();///撤销元素病释放内存
void reallocate();///获得更多内存并且拷贝已有元素 string *elements;///指向数组首元素的指针
string *first_free;///指向数组第一个空闲元素的指针
string *cap;///指向数组尾后位置的指针
}; void show(); #endif // STRVEC_H_INCLUDED

----

 #include "StrVec.h"
using namespace std; allocator<string> StrVec::alloc; void show(){
std::cout<<"from StrVec.cpp"<<std::endl;
} void StrVec::push_back(const string& s){
chk_n_alloc();/// alloc.construct(first_free++,s);
} ///函数返回一个pair,两个指针分别指向新空间的开始位置和拷贝的尾后位置,即data是新空间开始的位置,uninitiated_copy()返回新空间拷贝的尾后位置
pair<string*, string*>
StrVec::alloc_n_copy(const string *b,const string *e){
auto data = alloc.allocate(e-b);
return make_pair(data,uninitialized_copy(b,e,data));
//return {data,unintialized_copy(b,e,data)};
} void StrVec::free(){
///can not pass a nullptr to deallocate(),if elements is 0,then free() do nothing
if(elements){
for(auto p = first_free;p != elements;/* */){
StrVec::alloc.destroy(--p);
}
StrVec::alloc.deallocate(elements,cap-elements);
}
} StrVec::StrVec(const StrVec &s){
auto newdata = alloc_n_copy(s.begin(),s.end());
elements = newdata.first;
first_free = newdata.second;
cap = newdata.second;
} StrVec::~StrVec(){
free();
} StrVec &StrVec::operator=(const StrVec &rhs){
///
auto data = alloc_n_copy(rhs.begin(),rhs.end());
free();///释放掉已有元素之前,调用alloc_n_copy缓存rhs的元素,这可以处理自我赋值
elements = data.first;
first_free = data.second;
cap = data.second; return *this;///
} /**
在重新分配内存的过程中移动而不是拷贝元素
我们reallocate()应该做些什么呢?
1,为一个新的,更大的string数组分配元素
2,在内存空间的前一部分构造,保存现有元素
3,销毁原来内存空间中的元素,并释放这块内存
*/ void StrVec::reallocate(){
auto newcapacity = size() ? *size():; auto newdata = StrVec::alloc.allocate(newcapacity); auto dest = newdata;
auto elem = elements; for(size_t i = ;i != size();i++){
StrVec::alloc.construct(dest++,std::move(*elem++));
} free(); elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}

-----main.cpp

#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include "StrVec.h"
using namespace std; int main()
{
show();
StrVec sv;
sv.push_back("aaa");
sv.push_back("bbb"); int length = sv.size();
string *ptr = sv.begin();
for(int i = ;i<length;i++){
cout<<*ptr++<<endl;
} StrVec svb(sv);
string *ptrb = svb.begin();
for(int i = ;i<svb.size();i++){
cout<<*ptrb++<<endl;
} StrVec svc = sv;
string *ptrc = svb.begin();
for(int i = ;i<svc.size();i++){
cout<<*ptrc++<<endl;
}
return ;
}

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

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. Windows底层开发前期学习准备工作

    1.若对Windows底层开发没有兴趣,不建议继续深究, 若有些兴趣可以继续. 2. 先广泛打基础,比如C/ASM/C++/MFC,再学习Windows核心编程,对R3上的一些开发有所熟悉,再系统的学 ...

  2. memcached for .net on windows

    memcached for windowshttp://www.cnblogs.com/dudu/archive/2009/07/19/1526407.htmlhttp://www.cnblogs.c ...

  3. 2017.12.20 Java中的 IO/XML学习总结 File类详细

    IO / XML 一.File类 1.定义/概念 Java是面向对象的语言,要想把数据存到文件中,就必须要有一个对象表示这个文件.File类的作用就是代表一个特定的文件或目录,并提供了若干方法对这些文 ...

  4. 漫谈 Clustering (2): k-medoids

    上一次我们了解了一个最基本的 clustering 办法 k-means ,这次要说的 k-medoids 算法,其实从名字上就可以看出来,和 k-means 肯定是非常相似的.事实也确实如此,k-m ...

  5. Python实现屏蔽敏感词

    一.需求 1. 有一个文件,里面有一些敏感词汇,用户输入一段话,若包含这些词,就用**代替,并输出 二.实现代码 f = open('lib.txt', 'r') result = '' f1 = i ...

  6. c语言中--typeof--关键字用法

    C语言中 typeof 关键字是用来定义变量数据类型的.在linux内核源代码中广泛使用. 下面是Linux内核源代码中一个关于typeof实例: #define min(x, y) ({ \ typ ...

  7. 爬虫 xpath etree自动补全页面

    aa = etree.HTML(response.content) bb = etree.tostring(aa) doc = etree.HTML(bb)

  8. Linux dmidecode命令

    1.linux系统自带的dmidecode工具查询服务器硬件信息 dmidecode 用于获取服务器的硬件信息,通常是在不打开计算机机箱的情况下使用该命令来查找硬件详细信息 这个命令可以查看内存的几乎 ...

  9. [译]The Python Tutorial#7. Input and Output

    [译]The Python Tutorial#Input and Output Python中有多种展示程序输出的方式:数据可以以人类可读的方式打印出来,也可以输出到文件中以后使用.本章节将会详细讨论 ...

  10. BFS:CF356C-Compartments

    C. Compartments time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...