STL源码剖析——空间配置器Allocator#1 构造与析构
以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 构造与析构的更多相关文章
- STL源码剖析 — 空间配置器(allocator)
前言 以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象都存放在容器之中. 你完全可以实现一个直接向硬件存取空间的allocator. 下面介绍的是SGI STL提供的配 ...
- STL源码剖析——空间配置器Allocator#2 一/二级空间配置器
上节学习了内存配置后的对象构造行为和内存释放前的对象析构行为,在这一节来学习内存的配置与释放. C++的内存配置基本操作是::operator new(),而释放基本操作是::operator del ...
- STL源码剖析——空间配置器Allocator#3 自由链表与内存池
上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请.但只是对其概念进行点到为止的认识,并未深入探究.这节就来学习一下自由链表的填充和内存池的内存分配机制. refil ...
- STL源码剖析(空间配置器)
前言 在STL中,容器的定义中都带一个模板参数,如vector template <class T, class Alloc = alloc> class vector {...} 其中第 ...
- STL源码剖析:配置器
作用:对内存的管理 接口:申请和释放 内容: 几个全局函数 一级配置器 二级配置器 准备知识 POD是什么: Plain Old Data简称POD,表示传统的C语言类型:与POD类型对应的是非POD ...
- STL学习笔记:空间配置器allocator
allocator必要接口: allocator::value_type allocator::pointer allocator::const_pointer allocator::referenc ...
- 《STL源码剖析》相关面试题总结
原文链接:http://www.cnblogs.com/raichen/p/5817158.html 一.STL简介 STL提供六大组件,彼此可以组合套用: 容器容器就是各种数据结构,我就不多说,看看 ...
- 面试题总结(三)、《STL源码剖析》相关面试题总结
声明:本文主要探讨与STL实现相关的面试题,主要参考侯捷的<STL源码剖析>,每一个知识点讨论力求简洁,便于记忆,但讨论深度有限,如要深入研究可点击参考链接,希望对正在找工作的同学有点帮助 ...
- STL源码剖析之空间配置器
本文大致对STL中的空间配置器进行一个简单的讲解,由于只是一篇博客类型的文章,无法将源码表现到面面俱到,所以真正感兴趣的码农们可以从源码中或者<STL源码剖析>仔细了解一下. 1,为什么S ...
随机推荐
- 常用spaceclaim脚本(二)
#创建一个草图 #第一个参数传入一个Frame对象 #通过一个点和两个向量创建Frame #Frame的类成员函数Create被重载 #重载函数1:Frame.Create(Point, Direct ...
- ubuntu之路——day10.4 什么是人的表现
结合吴恩达老师前面的讲解,可以得出一个结论: 在机器学习的早期阶段,传统的机器学习算法在没有赶超人类能力的时候,很难比较这些经典算法的好坏.也许在不同的数据场景下,不同的ML算法有着不同的表现. 但是 ...
- C#作业处理
2019.9.8 作业要求: 将字符串加密,即将字符串中每个字符向后移动五个字符,并输出密文 解决方案: using System; using System.Collections.Generic; ...
- ADO.NET五大对象增删改查使用
string ConnStr = "Data Source=.;Initial Catalog=ADO_DEMO;Integrated Security=True"; #regio ...
- 范仁义web前端介绍课程---3、课程大纲(初步)
范仁义web前端介绍课程---3.课程大纲(初步) 一.总结 一句话总结: 知识点脉络(知识架构):刚开始对这个稍微了解一下就可以了,在逐步的学习过程中,心里大概有这样一套知识点的脉络 二.范仁义前端 ...
- 常见的医学基因筛查检测 | genetic testing | 相癌症早筛 | 液体活检
NIPT, Non-invasive Prenatal Testing - 无创产前基因检测 (学术名词) NIFTY,胎儿染色体异常无创产前基因检测 (注册商标)华大的明显产品 新生儿耳聋基因检测 ...
- 文章后面的QA或FAQ
QA:question&answer FAQ: Frequently Asked Questions的缩写,中文意思就是“经常问到的问题”
- PHP 输出两个指定日期之间的所有日期
function printDates($start,$end){ $dt_start = strtotime($start); $dt_end = strtotime($end); while ($ ...
- 013-docker-安装-Centos7
1.搜索镜像 docker search centos 2.拉取合适镜像 选择合适tag:https://hub.docker.com/,下载合适版本 docker pull centos:6.6 d ...
- SeetaFace2 cmake VS2015编译编译
cmake Selecting Windows SDK version 10.0.17134.0 to target Windows 10.0.18362. == BUILD_VERSION: v2. ...