C++ allocator

http://www.cnblogs.com/wpcockroach/archive/2012/05/10/2493564.html

说一说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 requirements20.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。

C++ allocator的更多相关文章

  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. Sitecore中Core,Master和Web数据库之间的区别

    Core数据库 正如名称所示,Core Database是Sitecore应用程序的主干,它可用于多种用途. 核心数据库包含所有Sitecore设置. 它包含桌面模式,内容编辑器,页面编辑器等的定义. ...

  2. QtQuick多页面切换、多页面切换动画、多个qml文件数据交互

    一.QtQuick多页面切换方法 (1)“隐藏法” 前一个视图visible设为false或者透明度opacity设为0,相当于“隐藏”了,实际还存在: 要显示的视图visible设为true或者透明 ...

  3. 2015全国大学生数学建模B题浅谈

    题目请自主上网获取. 分析下思路.第一问,不同时空的出租车的“供求匹配”程度. 也就是说要选取的数据要有时间和地理两个维度.实体对象是出租车.关键的问题就是地点怎么选? 选择的城市具备如下经济较发达, ...

  4. Linux firewalld 防火墙

    Linux firewalld 防火墙  简介 RHEL 7 系统中集成了多款防火墙管理工具,其中 firewalld(Dynamic Firewall Manager of Linux system ...

  5. ASP.NET MVC:缓存功能的设计及问题

    这是非常详尽的asp.net mvc中的outputcache 的使用文章. [原文:陈希章 http://www.cnblogs.com/chenxizhang/archive/2011/12/14 ...

  6. HTML5的自定义属性的使用总结

    https://blog.csdn.net/qq_31851435/article/details/53100691 <div id="myDiv" data-attribu ...

  7. centos etcd 启动失败

    chmod -R 777 /var/lib/etcd systemctl daemon-reload cat /etc/systemd/system/etcd.service " [Unit ...

  8. linux --- 8. mysql数据库,redis 数据库

    一. mysql 数据库 1.安装方式 ①yum安装 ②源代码编译安装 ③rpm包安装 yum安装的前提条件,是准备好yum源,可以选择163源,清华源,阿里云源,等等等 .安装mariadb的yum ...

  9. ant_<target>标签含义与使用

    <target>标记目标 目标是一个或多个任务的集合,任务是一段可执行的代码:构建文件中包含一个项目,在项目内部声明了所有目标: <target name = "run&q ...

  10. HDU 4010 Query on The Trees(动态树)

    题意 给定一棵 \(n\) 个节点的树,每个点有点权.完成 \(m\) 个操作,操作四两种,连接 \((x,y)\) :提 \(x\) 为根,并断 \(y\) 与它的父节点:增加路径 \((x,y)\ ...