allocator(C++帮助文档中size_type,value_type,allocator_type的含义)

本文目录
- C++帮助文档中size_type,value_type,allocator_type的含义
- C++类内使用allocator的问题
- STL allocator何时释放内存
- C++中的vector里的allocator是用来干吗的
- template
> 是什么意思,如何理解 - C++内存篇(三):allocator——申请未构造内存,根据需要在上面创建对象
- 公司的allocator是做什么的
- c++的allocator中的max_size()函数,解释一下
C++帮助文档中size_type,value_type,allocator_type的含义
size_type
由string类类型和vector类类型定义的类型,用以保存任意string对象或vector对象的长度,标准库类型将size_type定义为unsigned类型
value_type
值类型
allocator_type
allocator类是C++的一个模板,它提供类型化的内存分配以及对象的分配和撤销。
C++类内使用allocator的问题
allocator《T》 a a可以为类型为T的对象分配内存
a.allocate(n) 分配一段原始的未构造的内存,可以保存n个T类型的对象
a.deallocate(p,n) 释放T*指针p中地址开始的内存,保存了n个类型为T的对象;p必须是allocate返回的指针,n必须是p创建时所要求的大小,必须保证这些指针调用过destroy
a.construct(p, args) p必须是T*指针,指向原始内存,args传递给构造函数
a.destroy(p) p位T*指针,对p执行析构函数(销毁)
使用须知:
不要使用未构造的内存,小心越界,释放之前一定要销毁,只能销毁真正构造了得元素
p(内存未构造)----》p(可以使用)---------》p(使用结束)------------》p(释放内存)
a.allocate(p) a.construct(p) a.destroy(p) a.deallocate(p)
指针不能为空
例子:
动态内存管理类StrVec模仿std::vector《std::string》
使用allocator分配内存
指针成员
-----------未构造元素------------
^ ^ ^
|elements |first_free |cap
elements 分配的内存的首元素
first_free 实际元素之后的位置(已构造元素的尾后元素,未构造元素的首元素)
cap 分配内存末尾之后的位置
allocator《string》内存分配器
方法:
alloc_n_copy 分配内存,拷贝元素
free 销毁元素,释放内存
chk_n_alloc 检查空间,不够则分配新内存
reallocate 分配心内存
定义:
class StrVec
{
public:
StrVec(): //默认初始化
elements(nullptr), first_free(nullptr), cap(nullptr){}
StrVec(const StrVec &s)//拷贝构造函数
{
//分配内存,大小与s一样
auto newdata = alloc_n_copy(s.begin(), s.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
StrVec &operator=(const StrVec &rhs)//拷贝赋值
{
//分配内存,大小与rhs一样
auto data = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
~StrVec()//析构
{free();}
void push_back(const std::string&)//拷贝元素(别告诉我你没见过这个名字)
{
chk_n_alloc(); //检查空间
alloc.construct(first_free++, s); //构造s的副本(注意后置递增)
}
size_t size() const {return first_free - elements;}
size_t capacity() const {return cap - elements;} //这些都是vector的名字,一个效果
std::string *begin() const{return elements;}
std::string *end() const{return first_free;}//前面解释过了
private:
Static std::allocator《std::string》 alloc;//分配元素
void chk_n_alloc()
{
if(size() == capacity()) //分配的内存用完
reallocate(); //重新分配
}
std::pair《std::string*, std::string*》 alloc_n_copy(const std::string*, const std::string*)
{
//分配空间
auto data = alloc.allocate(e - b);
return {data, uninitialized_copy(b, e, data)};
}
void free() //销毁元素释放内存
{
//不能传递给deallocate一个空指针,如果为零,函数不作为
if(elements)
{
//逆序销毁旧元素(析构)
for (auto p = first_free; p != elements;/*空下*/)
alloc.destory(--p);//这里先递减,递减后的指针销毁
//这里释放内存空间
alloc.deallocate(elements, cap - elements);
}
}
void reallocate()//重新分配内存
{
//分配两倍的空间
auto newcapacity = size() ? 2 * size() : 1;
//1的作用是因为0 * 2 = 0,使空元素分配一个空间
auto newdata = alloc.allocate(newcapacity);
//将数据从旧内存移动到新内存
auto dest = newdata;
auto elem = elements;
for(size_t i = 0;i != size(); ++i)
alloc.construct(dest++, std::move(*elem++));
free();
//更新数据结构
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
std::string *elements;
std::string *first_free;
std::string *cap;//前面讲过
};
STL allocator何时释放内存
说一说C++里的allocator。我们知道,C++STL里定义了很多的容器(containers),每一个容器的第二个模板参数都是allocator类型。比方说在VC10里,vector类的模板声明为:template》classvector但是,基本上很少有人会自定义一个allocator。一来,默认的allocator已经够用了;二来,确实不知道该怎么用。一般来说,我们没有必要重新定义一个allocator。自定义的方式主要是为了提高内存分配相关操作的性能。而STL提供的方式性能已经足够好了。事实上,在windows平台上,new的底层实现是基于C语言的malloc函数;malloc函数家族又是基于WindowsHeapCreate、HeapAlloc、HeapFree等相关API来实现的(具体可以参考%VSInstallFolder%VCcrtsrc目录中的heapinit.c、malloc.c和new.cpp等相关函数)。先撇开性能的问题不说,我们看一看如何实现一个自己的allocator。在C++2003标准文档里,关于allocator的说明其实并不多,大概就20.1.5Allocatorrequirements和20.4.1Thedefaultallocator两处主要位置。虽然内容不多,但是足够我们写出一个自己的allocator。根据Allocatorrequirements我们需要提供一些typedefs:1:template2:classCHxAllocator3:{4:public:5://typedefs6:typedefTvalue_type;7:typedefvalue_type*pointer;8:typedefvalue_type&reference9:typedefvalue_typeconst*const_pointer;10:typedefvalue_typeconst&const_reference;11:typedefsize_tsize_type;12:typedefptrdiff_tdifference_type;13:14://rebind15:templatestructrebind{typedefCHxAllocatorother;};16:};在这里有一个比较不太容易理解的东西:rebind。C++标准里这么描述rebind的:Thememberclasstemplaterebindinthetableaboveiseffectivelyatypedeftemplate:ifthenameAllocatorisboundtoSomeAllocator,thenAllocator::rebind::otheristhesametypeasSomeAllocator.啥意思?可以用一个简单的例子来说明下:学校都学过数据结构,比方说栈、单向列表、树。我们就拿栈和列表来对比,看看有什么大不一样的地方。撇开数据结构上的差异,从allocator的角度来看,我们可以发现:堆栈是存贮元素本身的,但是列表实际上不是直接存储元素本身的。要维护一个列表,我们至少还需要一个所谓的next的指针。因此,虽然是一个保存int的列表list,但是列表存储的对象并不是int本身,而是一个数据结构,它保存了int并且还包含指向前后元素的指针。那么,list》如何知道分配这个内部数据结构呢?毕竟allocator只知道分配int类型的空间。这就是rebind要解决的问题。通过allocator::rebind()你就可以创建出用于分配_Node类型空间的分配器了。接下来要提供其他的接口。根据Thedefaultallocator的描述,我们要提供如下一些接口:pointeraddress(referenceval)constconst_pointeraddress(const_referenceval)const返回val的地址pointerallocate(size_typecnt,CHxAllocator::const_pointerpHint=0)分配空间。类似malloc。pHint可以无视,主要是给类库使用,用于提高性能。voiddeallocate(pointerp,size_typen)释放空间,类似free。size_typemax_size()constthrow()可分配的最大数量。voidconstruct(pointerp,const_referenceval)在地址p所指向的空间,使用val进行填充。需要使用到palcementnew,以便保证调用到构造函数。voiddestroy(pointerp)析构p指向的内存块中内容。一般通过显示调研析构函数来执行。allocator()throw()allocator(const_reference)throw()templateallocator(CHxAllocatorconst&)throw()~CHxAllocator()throw()各种构造函数和析构函数如何实现上面这些函数,你只要照抄标准库中的实现就可以了。如果你想要用c的malloc和free来实现,也可以这么写:1:pointerallocate(size_typecnt,CHxAllocator::const_pointerpHint=0)2:{3:UNREFERENCED_PARAMETER(pHint);4:5:if(cnt~T();32:}基本上,我们就简单实现了一个自己的allocator。另外,除了这些最主要的接口函数,你还需要实现比较操作符==和!=,但是这些函根据标准文档,都直接返回true和false。开头已经说了,重写allocator的主要目的是为了提高性。那怎样才能提高性能呢?直接使用Windows的HeapXXXX堆内存API?其实,你自己用一下就会发现,性能提升并不明显。因为通过new,再通过malloc,最后通过HeapAlloc不比直接调用HeapAlloc多几句话。如何实现一个高性能的allocator,需要借助memorypool的想法。另外,侯捷的stl源码剖析里分析了SGISTL利用类似想法实现的一个alloc。
C++中的vector里的allocator是用来干吗的
C++标准库的容器都有allocator成员,allocator是一个模板类,它的作用和C++中的new表达式是一样的(就是那个new、delete表达式),用于指定类型对象的内存分配,现代C++程序推荐使用allocator类,它比new更安全更灵活(官方的说法),它和new表达式的区别是new表达式分配的是未类型化的内存,而allocator类提供的是类型化的内存分配。如果你实在是搞不明白,就按照官方的说法,尽量多用allocator类。
template> 是什么意思,如何理解
C++模板的声明
你看到这个应该是STL中容器(vector, list)的代码
这个模板包含两个模板参数,T 和 Allocator。其中 Allocator 有 缺省值,缺省为 allocator《T》
allocator 也是一个模板,需要一个参数,你可以具体看它的定义,allocator《T》 为 模板allocator的实例。
要想看懂STL,需要一定的模板功底,推荐阅读 《C++ Template》。
C++内存篇(三):allocator——申请未构造内存,根据需要在上面创建对象
我们知道用new可以来进行动态大小的内存分配,在分配内存的同时new也会完成构造对象这个过程。
在分配单个我们知道要什么值的对象的内存时,这很方便。
然而如果我想要一大块内存——比如说我可能要存放几千个对象,于是我先去申请一万个对象的内存,我现在不知道我要取一万个什么值,也不知道具体最后会用多少个对象。这时我如果用new的话,会对所有申请的内存创建对象并赋予他们一些没有用的初始值,那些最后没有用到的内存 白白浪费了很多个创建对象操作 ,后来用到的对象值被修改的内存也 白白浪费了很多个赋值操作。
而且更重要的是, 有一些类没有默认构造函数,这样它们是不能用new来动态分配数组的。
这时候我希望先给我一大块内存而不要做别的,等我需要时再去上面创建对象和初始化。完成这种功能的东西就是 allocator 。
首先 allocator 类放在头文件 memory 中,于是你要先include它:
涉及三个关键字:
现在我想要一个为我分配 string 类型的内存的 allocator ,我称它为 AS :
《》 里也可以是 int , char , double ......任意你想要的对象类型。
现在我想要申请一万个 string 的内存空间:
我用 allocate(10000) 让 AS 为我分配还没有构造的(unconstructed)能放10000个 string 的连续内存, AS 完成了这个工作,并且返回一个指向这一块内存的首地址给指针 p 。我希望 p 记住这个首地址在哪免得我后边找不到了,所以我把它设为 const 的。
下面我让 AS 为我在这些内存上构造对象: AS.construct(内存地址,参数......) ,括号里的“参数”是给我这块内存的对象类型的构造函数的参数,比如这里对于 string ,可以这样:
这里我把参数 10 和 ’a’ 传给 string 的构造函数,所以我在首地址上构造了一个内容为 "aaaaaaaaaa" 的 string 。
也可以是其他的构造方法:
这样一来,我分别在我申请的内存上的第0个、第1个、第2个地址上构造出了 "aaaaaaaaaa" 、 "我的string" 、 "" 。
涉及两个关键字:
当我们用完对象后,对于每个构造出来的元素都要用 destroy(内存地址) 来销毁它:
元素销毁后,它所在的内存回到未构造状态,我们可以把它们拿来构造新的对象。
归还内存前我们必须把在上面的所有对象 destroy 掉,然后我之前申请了10000块内存,现在归还的数量也必须还是10000:
deallocate 接受两个参数,第一个是之前我们保存的申请的这块内存的首地址,第二个是归还的数量。注意 归还时给出的首地址和内存块数量必须和申请时一模一样 ,否则可能会造成 内存泄漏 噢。
公司的allocator是做什么的
C++标准库的容器都有allocator成员,allocator是一个模板类,它的作用和C++中的new表达式是一样的(就是那个new、delete表达式)。
分配器也被设计成促进全功能内存管理器的发展,但事实表明那种方法在STL的一些部分会导致效率损失。为了避免效率冲击,C++标准委员会向标准中添加了词语,把分配器弱化为对象,同时也表达了他们不会让操作损失能力的希望。
更新:
c++标准库的标准化始于1989年,由国际标准化组织(the International Organization for Standardization,ISO)推动。至今完成了四个标准,那就是各种C++ standard。
c++981998年批准,是第一份C++标准。文档编号ISO/IEC 14882:1998。
c++03是一份“技术勘误”,修复了几个小bug,文档编号ISO/IEC 14882:2003。
TR1内含大尺度的标准库扩充,文档编号ISO/IEC TR 19768:2007。
c++11对c++内含语言或/和标准库两方面皆十分重大的改善和强化。文档编号ISO/IEC 14882:2011。
c++的allocator中的max_size()函数,解释一下
vector
存在预分配机制。可以在元素不存在的情况下预分配一段空间,为以后的存储做准备。这段空间可以用reserve()调节。capacity()返回的值就是可以存放元素的个数。capacity()
-
size()就是下次重新进行空间分配前的预留元素个数。至于max_size()指的是一个vector结构可供储存元素的个数的上线,通常是由于寻址空间决定的。

本文相关文章:
把图片转换成word文档的软件(把图片文字转换成word文档的软件)
2026年7月4日 03:50
plsql连接oracle时database(plsql怎么连接oracle)
2026年10月6日 09:30
html中ahref(HTML中:或者 ,href后面直接跟“/“或者是“/products/“是什么)
2026年9月21日 14:40
formulate是什么意思(formulate是什么意思中文翻译)
2026年9月20日 16:50
app下载软件免费(怎样去appstore下载免费软件不用密码)
2026年9月18日 20:20
winform下拉框(C# winform 下拉列表控件(comboBox))
2026年9月18日 06:30
更多文章:
teammate(teammate,company,partner)
2026年10月11日 06:10
javascript arraybuffer(javascript可以把base64编码转换成二进制代码吗求示例代码!)
2026年10月11日 04:00
text函数公式(excel中round和text函数的区别是什么)
2026年10月11日 03:50
google chrome打不开(chrome浏览器打不开怎么回事 浏览器打不开的处理方法)
2026年10月11日 02:00
websocket整合springboot(Springboot整合Websocket遇到的坑)
2026年10月11日 01:40
drawerlayout(android 怎样让drawerlayout设置的侧滑菜单的内容充满屏幕)
2026年10月10日 19:20
xor四位数怎么运算(单片机怎样用C语言实现4个数字间的异或)
2026年10月10日 17:50
perl数组中最多的元素(用perl实现,得到一个数组中重复次数最多的元素)
2026年10月10日 17:00


