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. shell bash-shell

    bash shell中的命令替换,`cmd`或者$(cmd). bash shell中的变量赋值,直接name = var:  (bash中的变量赋值不能中间有空格) 变量引用时,$name,如果na ...

  2. pypi上传命令

    windows 1.新建一个setup.py文件与你自己写的.py模块放在一个文件夹内 内容: from distutils.core import setup setup( name = " ...

  3. 使用addeventlistener为js动态创建的元素添加事件监听

    点击li弹出内容,并且动态添加li之后有效 <button onclick="addFunction()">点我增加</button> <ul> ...

  4. Beaglebone板子修改usb连接时的默认IP192.168.0.2

    首先除了有个USB线外,你还需要一个USB转串口的线(目的是防止修改错误,无法使用原来的usb的IP地址登陆,心大的可以跳过这步直接进入重点),串口线连接方法如下图: ​ 将USB以及串口和PC机相连 ...

  5. K8S学习笔记之Kubernetes 部署策略详解

    0x00 概述 在Kubernetes中有几种不同的方式发布应用,所以为了让应用在升级期间依然平稳提供服务,选择一个正确的发布策略就非常重要了. 选择正确的部署策略是要依赖于我们的业务需求的,下面我们 ...

  6. centos7.3配置python2、3环境与配置各自pip

    环境:CentOS-7-x86_64-Everything-1611 No.1 查看CentOS对Python的默认依赖 [root@cs ~]# ls /usr/bin/python* /usr/b ...

  7. 树莓派3B安装LEDE

    本来想安装openwrt的,但是op官方没有支持pi3,甚至op都不怎么发新版了,仅LEDE分支有缓慢的更新..离题了,之前给pi3装过LEDE,体验不是很好.今天到openwrt官网看了下,发现之前 ...

  8. java基础hashmap

    Iterator中hasNext(), next() 在Iterator类中,我们经常用到两个方法: hasNext(), next(),具体含义: next(),  是返回当前元素, 并指向下一个元 ...

  9. (转)GANs and Divergence Minimization

    GANs and Divergence Minimization 2018-12-22 09:38:27     This blog is copied from: https://colinraff ...

  10. sql添加一个list的查询条件

    编程中往往会有需要对某个list的值进行查询的需求,而将一个list作为查询条件,我所知道的有两种方法: 1.for循环遍历,每次循环一个sql,每次查list中一个条件的数据,最后累加 ...(最基 ...