以STL的运用角度而言,空间配置器是最不需要介绍的东西,因为它扮演的是幕后的角色,隐藏在一切容器的背后默默工作。但以STL的实现角度而言,最应该首先介绍的就是空间配置器,因为这是这是容器展开一切运作的基石。空间配置器顾名思义就是配置空间的器件,为存放在容器里的信息找到安家落户的地方(内存)。

  SGI STL上有两个空间配置器,一个是std::allocator,一个是std::alloc,前者只是单纯的把基层的内存配置/释放行为(::operator new 和 ::operator delete)做了一层简单的封装,不作总结;后者才是我们应该重点学习的对象。

  一般而言,C++的内存配置与释放操作是这样的:

 class Foo {...};
Foo* pf = new Foo;
delete pf;

  其中的new包含两阶段的操作:(1)调用::operator new分配内存;(2)调用Foo::Foo()构造对象内容。delete也包含两阶段的操作:(1)调用Foo::~Foo()将对象析构;(2)调用::operator delete释放内存。。

  而在std::alloc中同理,内存配置操作由alloc::allocate()负责,释放由alloc::deallocate()负责;对象构造操作由::construct()负责,析构由::destroy()负责。而这两组函数分别在两个头文件里,而这两个头文件又被<memory>所包含:

  •   #include<stl_alloc.h>    //负责内存空间的配置与释放
  •   #incluce<stl_construct.h>  //负责对象内容的构造与析构

 

  从这幅图中能大致看出空间配置器的概貌,本文先就从<stl_construct.h>出发学习空间配置器中对象的构造与析构。

  

 //<stl_construct.h>的部分内容

 #include <new.h>        // 欲使用 placement new,需先含包含此文件

 template <class T1, class T2>
inline void construct(T1* p, const T2& value) {
new (p) T1(value); // placement new; 喚起T1::T1(value);
} /*new (p) T1(value); 是指在p所指的内存上调用T1的构造函数,把其产生的对象存放在p所指内存里。而T1::T1(value);说明T1构造函数的形参为const T2 &(一个T2类型的常引用变量)。*/ // 以下是 destroy() 第一版本,接受一個指標。
template <class T>
inline void destroy(T* pointer) {
pointer->~T(); // 喚起 dtor ~T()
} // 以下是 destroy() 第二版本,接受兩個迭代器。此函式是設法找出元素的數值型別,
// 進而利用 __type_traits<> 求取最適當措施。
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
__destroy(first, last, value_type(first));
} // 判斷元素的數值型別(value type)是否有 trivial destructor
template <class ForwardIterator, class T>
inline void __destroy(ForwardIterator first, ForwardIterator last, T*) {
typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
__destroy_aux(first, last, trivial_destructor());
} // 如果元素的數值型別(value type)有 non-trivial destructor…
template <class ForwardIterator>
inline void
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) {
for ( ; first < last; ++first)
destroy(&*first);
} // 如果元素的數值型別(value type)有 trivial destructor…
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {} // 以下是destroy() 第二版本針對迭代器為 char* 和 wchar_t* 的特化版
inline void destroy(char*, char*) {}
inline void destroy(wchar_t*, wchar_t*) {}

  

  construct()接受一个指针p和一个初值value,该函数的作用就是将value作为实参在指针所指的空间上调用构造函数产生对象。关于placement new相关知识可以浏览这篇博客

  destroy()有两个版本,第一个版本很简单,直接调用该对象的析构函数即可。而第二个版本就稍微复杂点,要把[first, last)范围内的所有对象析构掉,这里涉及到一个问题,如果范围很大,但对每个对象的析构函数都无关痛痒,那么一次次调用这些无关痛痒的析构函数会造成性能上的损失。因此,这里首先利用value_type()获得迭代器所指对象的类型,再利用__type_traits<T>判断该类型的析构函数是否无关痛痒。若是(__true_type),则什么也不做;若否(__false_type),这才以循环的方式遍历整个区间范围,并逐一调用每一个对象上析构函数。而对于如何实现获得迭代器所指之物的类型和如何实现判断析构函数是否无关痛痒将在学习trait编程时有所提及。

STL源码剖析——空间配置器Allocator#1 构造与析构的更多相关文章

  1. STL源码剖析 — 空间配置器(allocator)

    前言 以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象都存放在容器之中. 你完全可以实现一个直接向硬件存取空间的allocator. 下面介绍的是SGI STL提供的配 ...

  2. STL源码剖析——空间配置器Allocator#2 一/二级空间配置器

    上节学习了内存配置后的对象构造行为和内存释放前的对象析构行为,在这一节来学习内存的配置与释放. C++的内存配置基本操作是::operator new(),而释放基本操作是::operator del ...

  3. STL源码剖析——空间配置器Allocator#3 自由链表与内存池

    上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请.但只是对其概念进行点到为止的认识,并未深入探究.这节就来学习一下自由链表的填充和内存池的内存分配机制. refil ...

  4. STL源码剖析(空间配置器)

    前言 在STL中,容器的定义中都带一个模板参数,如vector template <class T, class Alloc = alloc> class vector {...} 其中第 ...

  5. STL源码剖析:配置器

    作用:对内存的管理 接口:申请和释放 内容: 几个全局函数 一级配置器 二级配置器 准备知识 POD是什么: Plain Old Data简称POD,表示传统的C语言类型:与POD类型对应的是非POD ...

  6. STL学习笔记:空间配置器allocator

    allocator必要接口: allocator::value_type allocator::pointer allocator::const_pointer allocator::referenc ...

  7. 《STL源码剖析》相关面试题总结

    原文链接:http://www.cnblogs.com/raichen/p/5817158.html 一.STL简介 STL提供六大组件,彼此可以组合套用: 容器容器就是各种数据结构,我就不多说,看看 ...

  8. 面试题总结(三)、《STL源码剖析》相关面试题总结

    声明:本文主要探讨与STL实现相关的面试题,主要参考侯捷的<STL源码剖析>,每一个知识点讨论力求简洁,便于记忆,但讨论深度有限,如要深入研究可点击参考链接,希望对正在找工作的同学有点帮助 ...

  9. STL源码剖析之空间配置器

    本文大致对STL中的空间配置器进行一个简单的讲解,由于只是一篇博客类型的文章,无法将源码表现到面面俱到,所以真正感兴趣的码农们可以从源码中或者<STL源码剖析>仔细了解一下. 1,为什么S ...

随机推荐

  1. 浅析TCP三次握手及四次挥手

    1. 三次握手 1. TCP为什么相较于UDP是可靠连接? 可靠连接是指,待通信的两个实体,能够满足通信数据包的有序性.完整性以及可靠性.对于UDP来说, 它的连接过程不需要握手,忽略丢失的数据包,并 ...

  2. Samba文件共享服务设置

    SMB的主程序 smbd:SMB-TCP139,CIFS-TCP445 nmbd:NetBios-UDP137,138 SMB主程序对应的两个服务 /etc/init.d/smb /etc/init. ...

  3. java判断A字符串中是否包含B字符

    java.lang.String类提供的方法 public boolean contains(CharSequence s) 当且仅当此字符串包含指定的 char 值序列时,返回 true. 例如: ...

  4. R绘制韦恩图 | Venn图

    解决方案有好几种: 网页版,无脑绘图,就是麻烦,没有写代码方便 极简版,gplots::venn 文艺版,venneuler,不好安装rJava,参见Y叔 酷炫版,VennDiagram 特别注意: ...

  5. JVM 主动类和被动类的使用

    主动使用和被动使用Demo 1.创建工程一个Gradle工程 下一步 下一步 点击完成 2.创建类 public class MyTest1 { public static void main(Str ...

  6. VS2010专业版和旗舰版(中文版)下载

    本文转载自https://blog.csdn.net/chy2z/article/details/80080399 注意: 中文版为iso镜像文件,使用 Daemon Tools 虚拟光驱软件载入进行 ...

  7. Vuejs函数式组件,你值得拥有(1)

    函数式组件在React社区很流行使用,那么在vue里面我们要怎么用呢 下面会涉及到的知识点: 高阶函数.状态.实例.vue组件 什么是函数式组件 我们可以把函数式组件想像成组件里的一个函数,入参是渲染 ...

  8. socat管理haproxy配置 ssh-keygen -N '' -t rsa -q -b 2048

    socat管理haproxy配置   haproxy是可以通过socat命令管理haproxy.cfg文件的:1.安装socat yum install socat -y 2.配置haproxy.cf ...

  9. 刷新指定窗口页面的gridTable数据

    top.frames[windowName].$("#gridTable").trigger("reloadGrid"); 其中”windowName即是窗口页 ...

  10. 积神经网络(CNN)的参数优化方法

    http://www.cnblogs.com/bonelee/p/8528863.html 积神经网络的参数优化方法——调整网络结构是关键!!!你只需不停增加层,直到测试误差不再减少. 积神经网络(C ...