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 ...
随机推荐
- FLUENT质量加权平均和面积加权平均的区别【转载】
转载自:http://blog.sina.com.cn/s/blog_7ef78d170101bhfn.html 网上关于fluent中质量加强平均(Mass-Weighted Average)和面积 ...
- Vue.js中 watch的理解以及深度监听
如代码: <div> <p>FullName: {{fullName}}</p> <p>FirstName: <input type=" ...
- 关于hexo与github使用过程中的问题与笔记
快速阅读 如何用github 和hexo 创建一个blog 1.github中要新建一个与用户名同一样的仓库, 如:homehe.github.io - 必须是io后缀.一个帐户 只能建立一个 2. ...
- mac安装rust的pyo3模块
Rust 发布的工具链包括了 stable.beta 和 nightly 三种不同版本. nightly 是最激进的版本,包含了大量(可能不稳定)的新/高级特性.stable 版本目前可能还不支持一些 ...
- Vue基础学习 --- 全局组件与局部组件
组件分为 全局组件 局部组件 全局组件 // 语法---Vue.component('组件名', {组件参数}) Vue.component('com1', { template: '<butt ...
- linux 查看gpu信息
- 关于如何重写Controller和Service技术攻关文档
版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39784756/articl ...
- QQ 有很多关于会员的标记,腾讯舍不得为每一个标记用 1 个字节 Byte,而用的是 1 比特 Bit。
17年的实践:腾讯海量产品的技术方法论-其它分享/专项技术区 - 即时通讯开发者社区! http://www.52im.net/thread-159-1-1.html 腾讯QQ1.4亿在线用户的技术挑 ...
- MiniUI表单验证实践
学习实践: <form id="form2"> <div id="update_pas" style="width:380px&qu ...
- TextView: android:ellipsize="marquee" 跑马灯效果无效的问题
今天练习的时候想实现一个文字的跑马灯效果,本来想自己手动实现的,不过突然想起来android里的TextView属性似乎自带了这个效果,叫: android:ellipsize ,平时都是把它的属性值 ...