问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

stl 内存分配器什么时候释放

发布网友 发布时间:2022-04-11 19:25

我来回答

2个回答

热心网友 时间:2022-04-11 20:55

说一说C++里的allocator。我们知道,C++ STL里定义了很多的容器(containers),每一个容器的第二个模板参数都是allocator类型。比方说在VC10里,vector类的模板声明为:
template<class _Ty, class _Ax = allocator<_Ty> >
class vector
但是,基本上很少有人会自定义一个allocator。一来,默认的allocator已经够用了;二来,确实不知道该怎么用。一般来说,我们没有必要重新定义一个allocator。自定义的方式主要是为了提高内存分配相关操作的性能。而STL提供的方式性能已经足够好了。事实上,在windows平台上,new的底层实现是基于C语言的malloc函数;malloc函数家族又是基于Windows HeapCreate、HeapAlloc、HeapFree等相关API来实现的(具体可以参考%VSInstallFolder%\VC\crt\src目录中的heapinit.c、malloc.c和new.cpp等相关函数)。
先撇开性能的问题不说,我们看一看如何实现一个自己的allocator。
在C++ 2003标准文档里,关于allocator的说明其实并不多,大概就20.1.5 Allocator requirements和20.4.1 The default allocator两处主要位置。虽然内容不多,但是足够我们写出一个自己的allocator。
根据Allocator requirements我们需要提供一些typedefs:
1: template <typename T>
2: class CHxAllocator
3: {
4: public:
5: // typedefs...
6: typedef T value_type;
7: typedef value_type* pointer;
8: typedef value_type& reference;
9: typedef value_type const* const_pointer;
10: typedef value_type const& const_reference;
11: typedef size_t size_type;
12: typedef ptrdiff_t difference_type;
13:
14: // rebind...
15: template <typename _other> struct rebind { typedef CHxAllocator<_other> other; };
16: };

在这里有一个比较不太容易理解的东西:rebind。C++标准里这么描述rebind的:
The member class template rebind in the table above is effectively a typedef template: if the name Allocator is bound to SomeAllocator<T>, then
Allocator::rebind<U>::other is the same type as SomeAllocator<U>.
啥意思?可以用一个简单的例子来说明下:
学校都学过数据结构,比方说栈、单向列表、树。我们就拿栈和列表来对比,看看有什么大不一样的地方。撇开数据结构上的差异,从allocator的角度来看,我们可以发现:堆栈是存贮元素本身的,但是列表实际上不是直接存储元素本身的。要维护一个列表,我们至少还需要一个所谓的next的指针。因此,虽然是一个保存int的列表list<int>,但是列表存储的对象并不是int本身,而是一个数据结构,它保存了int并且还包含指向前后元素的指针。那么,list<int, allocator<int>>如何知道分配这个内部数据结构呢?毕竟allocator<int>只知道分配int类型的空间。这就是rebind要解决的问题。通过allocator<int>::rebind<_Node>()你就可以创建出用于分配_Node类型空间的分配器了。
接下来要提供其他的接口。根据The default allocator的描述,我们要提供如下一些接口:
pointer address(reference val) const
const_pointer address(const_reference val) const
返回val的地址
pointer allocate(size_type cnt, CHxAllocator<void>::const_pointer pHint = 0) 分配空间。类似malloc。pHint可以无视,主要是给类库使用,用于提高性能。
void deallocate(pointer p, size_type n) 释放空间,类似free。
size_type max_size() const throw() 可分配的最大数量。
void construct(pointer p, const_reference val) 在地址p所指向的空间,使用val进行填充。需要使用到palcement new,以便保证调用到构造函数。
void destroy(pointer p) 析构p指向的内存块中内容。一般通过显示调研析构函数来执行。

allocator() throw ()
allocator(const_reference) throw ()
template <typename _other> allocator(CHxAllocator <_other> const&) throw()
~CHxAllocator() throw()
各种构造函数和析构函数

如何实现上面这些函数,你只要照抄标准库中的实现就可以了。如果你想要用c的malloc和free来实现,也可以这么写:
1: pointer allocate(size_type cnt, CHxAllocator<void>::const_pointer pHint = 0)
2: {
3: UNREFERENCED_PARAMETER(pHint);
4:
5: if (cnt <= 0)
6: {
7: return 0 ;
8: }
9:
10: void* pMem = nullptr ;
11: if (max_size() < cnt || (pMem = malloc(cnt * sizeof(value_type))) == NULL)
12: {
13: throw std::bad_alloc(0);
14: }
15:
16: return static_cast <pointer>(pMem);
17: }
18:
19: void deallocate(pointer p, size_type)
20: {
21: free(p);
22: }
23:
24: void construct(pointer p, const_reference val)
25: {
26: :: new ((void *)p) T(val);
27: }
28:
29: void destroy(pointer p)
30: {
31: p->~T();
32: }

基本上,我们就简单实现了一个自己的allocator。另外,除了这些最主要的接口函数,你还需要实现比较操作符==和!=,但是这些函根据标准文档,都直接返回true和false。
开头已经说了,重写allocator的主要目的是为了提高性。那怎样才能提高性能呢?直接使用Windows的HeapXXXX堆内存API?其实,你自己用一下就会发现,性能提升并不明显。因为通过new,再通过malloc,最后通过HeapAlloc不比直接调用HeapAlloc多几句话。如何实现一个高性能的allocator,需要借助memory pool的想法。另外,侯捷的stl源码剖析里分析了SGI STL利用类似想法实现的一个alloc。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
...开始是大腿内侧,后是大腿跟上,脖子后面,再就是肚子上,现在几乎... 工程土方定额里面:人力 运输距离 0.5km以内 20m以内是什么意思 ...由诸葛亮著的《诫子训》中摘录的,问您是如何理解的?! 手把手带你将 Linux 主机配置为静态路由器 Linux配置路由功能及添加静态路由 Linux模拟路由器从实现网络模拟到运行路由器linux模拟路由器 幼儿园中班学期结束家长会稿子怎么写 幼儿园中班期末家长会的发言稿 女人在哪个年龄段性俗最强 谁知道女人多大性欲最高? the internet is important作文 web-accessible 是什么意思 想给我家的E70上前端,有推荐的吗 runescape item,runescape account,runescape power leveling 这些是什么? 麻烦英语好的大哥帮忙翻译一下~跪谢了! 找个高手帮我翻译一下,不要百度谷歌翻译 翻译汉语课文成英文 一百分拿下它 请大家帮忙人工翻译一篇摘要,最好是英语很好的,直接通过在线翻译的就别帖上来啦,谢谢;急用。 网络资源带给人们的好处英语作文 想找一篇关于《网络营销与传统营销的比较研究》的外文文献和翻译 求一个PVP为主的魔兽世界私服 C#如何保存多个textbox的值到一个文件,然后可以提取文件到多个textbox里 请求专家 关于 法语 过去将来时用法的2 道题. 中文翻法文 ! 需要法文高手进来!!! 急急急 不要翻译软体 part2 求3DMAX9快捷文档,新手基础入门,急用,我QQ108495245,英文版本的 红葡萄酒应怎样喝才更健康? 喝哪種紅酒比較養顏? 求IE6浏览器专用的css hack(即该部分语句只对IE6有效) c#怎么提取xml里的某几行数据? 麻烦哪位高人帮忙把我这篇中文翻译成法文,万分感谢,时间紧迫,急求! 动态声请内存,操作系统会做哪些事情? 0x77dl8d8a指令引用的0x003d84f4内存,该内存不能为read 什么是嵌入式系统的好的C 内存分配器 &quot;0x7c9308d3&quot;指令引用的&quot;0x01c17008&quot;内存。该内存不能为&quot;written&quot;。 C++语言中,new表示什么的关键字? C语言中动态内存分配的问题 int * p=(int*)malloc(8) 这样理解对不对:(in 【C/C++】如何判断指针式malloc/new分配出来的 SAP 如何连接 DB2? sap ides with db2 如何扩展表空间 sap环境下搞db2的hadr是不是有特殊要求 学SAP需要oracle数据库的知识和linux系统的知识吗? sap的后台主流的数据库一般都是oracle的吗?还有其他的数据库吗? sap系统应该怎么选择 cocos2dx中label为什么不支持中文 Cocos2dx 3.1.1 半透明的Layer中如何实现屏蔽后面层的事件(屏蔽层)(不用CocoStudio的json文件)? cocos2dx 3.1 vs里怎么配置cocostudio cocos2dx3.1怎么编译 求助Cocos2dx 3.1 读取Cocos Studio 1.6 的UI slider的问题 cocos2dx3.1 xcode 怎么新建文件,选择基类 cocos2dx3.1 lua绑定c++类中怎么出错了