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. Windbg程序调试系列2-内存泄露问题

    上篇文章给大家解释了Windbg的基本命令和说明,这一篇给大家介绍内存泄露场景的问题分析. 文章大纲: 描述问题背景和现象 确定问题是否是内存泄露 梳理问题分析思路 动手分析解决 总结 1. 先说问题 ...

  2. 使用quartz数据库锁实现定时任务的分布式部署

    ,1.根据项目引用的quartz依赖版本,确定下载的quartz-distribution安装包,我项目引用的信息如下图所示: 2.解压,在\quartz-2.2.3-distribution\qua ...

  3. JavaScript 声明提前机制

    声明提前机制 在JavaScript存在着这样一种预处理机制,即浏览器在解析JS代码时会将var声明的变量和function声明的函数提升到当前作用域的顶部.但是解析JS代码时对var和functio ...

  4. Spring 工具包

    Spring 工具包: spring-core-.RELEASE.jar!\org\springframework\util

  5. Spring 集成 Swagger UI

    <!-- Spring --> <dependency> <groupId>org.springframework.boot</groupId> < ...

  6. 复习-css边框和背景属性

    css边框和背景属性 border:所有边框属性 border-width:四条边框的宽度 border-style:设置边框样式,主要有dotted.solid.double border-colo ...

  7. chrome内核浏览器插件的使用--Tampermonkey(油猴插件)

    Tampermonkey(油猴插件),这个插件是一个用于改造你浏览器打开的网站的插件.它可以在你打开的网页中注入任意js脚本,以达到你想要的外加功能.可以说非常不错.很多时候也值得使用. 这是个chr ...

  8. spring boot +mybatis 整合 连接数据库测试(从0到1)

    spring boot 整合mybatis 1.打开idea创建一个项目 2.在弹出的窗口中选择spring initializr(初始化项目),点击next 3.接下来填写group 与artifa ...

  9. Hadoop数据类型

    hadoop包装了java的基本数据类型使他们实现以上的接口而且给予实现细节,这些类都实现了WritableComparable接口,能够在不同的hadoop节点之间毫无障碍的传输了.

  10. Qt 从菜单栏打开文件

    Qt从菜单栏的下拉菜单选择文件 构造函数中设置打开动作信息 //打开文件 m_menu = ui.menu; // m_menu->menuAction = new QAction(QIcon( ...