前言

SGI STL将new的申请空间和调用构造函数的两个功能分开实现, 如果对new不太清楚的, 可以先去看看这一篇new实现再来看配置器也不迟. 本节是STL分析的第一篇, 主要分析STL各个部分都会出现的alloc实现, 虽然每个部分都只会默认调用它, 不了解它也可以看懂分析, 但是他又是不可缺少的, 我们就以它做为开篇进行分析.

"new"的实现

这里直接我们直接来看STL的construct实现吧

   // 这里的construct调用的是placement new, 在一个已经获得的内存里建立一个对象
template <class T1, class T2>
inline void construct(T1* p, const T2& value)
{
new (p) T1(value);
}

可以明白这里就只是一个placement new的调用, 只是用了泛型来实现一个对象分配的模板, 并实现初始化.

既然已经看到了对象的分配, 那再接再厉看看空间的分配, 充分了解STL是怎么将new分开执行的. allocate函数实现空间的申请, 但是这里有一点看不出来, 申请内存是有分为一级配置器和二级配置器, 分配的空间小于128字节的就调用二级配置器, 大于就直接使用一级配置器, 一级配置器直接调用malloc申请, 二级使用内存池.

   template<class T>
inline T* allocate(ptrdiff_t size, T*)
{
set_new_handler();
T* tmp = (T*)(::operator new(size)(size * sizeof(T)));
if(!tmp)
{
cerr << "out of memort" << endl;
exit();
}
return tmp;
}

内存分配果然是调用operator new来执行空间分配, 这里allocate和construct都只是简单的对operator new进行封装.

   const int N = ;
int main()
{
allocator<string> alloc;
auto str_ve = alloc.allocate(N);
auto p = str_ve; // vector<string> *p = str_ve;
alloc.construct(p++);
alloc.construct(p++, , 'a');
alloc.construct(p++, "construct");
cout << str_ve[] << endl; // " "空的
cout << str_ve[] << endl; // aaaaaaaaaa
cout << str_ve[] << endl; // construct while(p != str_ve)
{
alloc.destroy(--p);
}
alloc.deallocate(str_ve, N);

exit();
}

这个程序首先调用allocate申请N个大小的空间, 在依次construct调用构造函数, 这里就先初始化3个结构, 紧接着通过destory调用析构函数, 最后deallocate释放申请的空间. 整个过程很容易理解, 但是这里还要深入是dealllocate和destroy两个函数.

"delete"实现

先是看destroy调用析构函数. 而destroy有两个版本.

版本一:

需要传入的参数 : 一个指针

  // 第一版本, 接收指针
template <class T> inline void destroy(T* pointer)
{
pointer->~T();
}

版本一直接就调用了析构函数, 不用过多的分析.

版本二:

需要传入的参数 : 两个迭代器

  // 第二个版本的, 接受两个迭代器, 并设法找出元素的类型. 通过__type_trais<> 找出最佳措施
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last)
{
__destroy(first, last, value_type(first));
}

// 接受两个迭代器, 以__type_trais<> 判断是否有traival 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());
}

destroy直接调用 __destroy, 前者只是一个接口, 所以重点是在后者.

分析 __type_traits<> : 它是用于获取迭代器所指对象的类型,运用traits技法实现的.只要记住我们用来获取对对象类型就可以了. 然后通过类型的不一样选择执行不同的析构调用.

__type_traits__false_type时, 调用的是下面这个函数, 通过迭代所有的对象并调用版本一的函数执行析构函数进行析构. 而这个是被称为non-travial destructor


  // 没有non-travial destructor
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
{
for ( ; first < last; ++first)
destroy(&*first);
}

__type_traits__true_type时, 什么也不做, 因为这样效率很高效, 并不需要执行析构函数. 而这个是被称为travial destructor.

  // 有travial destructor
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}

最后是版本二的特化版, 同样也什么都不用做, 没有必要做析构.

  inline void destroy(char*, char*) {}
inline void destroy(wchar_t*, wchar_t*) {}

destroy分为这么几个版本和几个不同的函数执行都是为了提升效率, 较小的调用并不能看出什么, 但是如果是范围析构的话这样不同的选择析构能很节约时间和效率.

讲解完了destory后应该就能明白上面代码循环执行析构函数了.


小结

这里用一个小小的例子来理解"new"和"delete"运算符, 理解new, delete每步分开执行, 内存释放(deallocate)这里没有讲解, 也只是简单的调用free函数. STL这样做1. 为了效率, 2. 为了构建内存池.

最后将所有的函数进行封装到allocator, 所以例子中都是调用的构造析构等都是封装在该类中.

STL源码分析之空间配置器的更多相关文章

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

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

  2. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

  3. STL源码分析之第一级配置器

    前言 上一节我们分析了空间配置器对new的配置, 而STL将空间配置器分为了两级, 第一级是直接调用malloc分配空间, 调用free释放空间, 第二级三就是建立一个内存池, 小于128字节的申请都 ...

  4. STL源码分析《3》----辅助空间不足时,如何进行归并排序

    两个连在一起的序列 [first, middle) 和 [middle, last) 都已经排序, 归并排序最核心的算法就是 将 [first, middle) 和 [middle, last) 在  ...

  5. MyCat源码分析系列之——配置信息和启动流程

    更多MyCat源码分析,请戳MyCat源码分析系列 MyCat配置信息 除了一些默认的配置参数,大多数的MyCat配置信息是通过读取若干.xml/.properties文件获取的,主要包括: 1)se ...

  6. STL源码分析《4》----Traits技术

    在 STL 源码中,到处可见 Traits 的身影,其实 Traits 不是一种语法,更确切地说是一种技术. STL库中,有一个函数叫做 advance, 用来将某个迭代器(具有指针行为的一种 cla ...

  7. STL 源码分析《1》---- list 归并排序的 迭代版本, 神奇的 STL list sort

    最近在看 侯捷的 STL源码分析,发现了以下的这个list 排序算法,乍眼看去,实在难以看出它是归并排序. 平常大家写归并排序,通常写的是 递归版本..为了效率的考虑,STL库 给出了如下的 归并排序 ...

  8. springMVC源码分析--RequestParamMethodArgumentResolver参数解析器(三)

    之前两篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)和springMVC源码解析--HandlerMethodArgumentResol ...

  9. STL源码分析之第二级配置器

    前言 第一级是直接调用malloc分配空间, 调用free释放空间, 第二级三就是建立一个内存池, 小于128字节的申请都直接在内存池申请, 不直接调用malloc和free. 本节分析第二级空间配置 ...

随机推荐

  1. dom小练习

    dom小练习 学习要点 综合运用学过的知识完成几个综合小练习,巩固学过的知识. 阶段小练习8-1:改变网页字体的大小 要求和提示: 要求:当用户选择‘大/中/小’的选项时,页面字体发生相应的变化 阶段 ...

  2. InfluxDB存储引擎Time Structured Merge Tree——本质上和LSM无异,只是结合了列存储压缩,其中引入fb的float压缩,字串字典压缩等

    The New InfluxDB Storage Engine: Time Structured Merge Tree by Paul Dix | Oct 7, 2015 | InfluxDB | 0 ...

  3. python-----文件自动归类

    如何移动文件? →  使用内置模块来实现 归类的规则是什么? → 手动(预设文件夹)/ 自动(创建文件夹) import shutil import os path = './' #由于这里是相对路径 ...

  4. MySQL 操作语句

    解释:|:或;{}:必选;[]:可选 创建数据库并指定字符编码: CREATE {DATABASE|SCHEMA} [IF NOT EXISTS] db_name [DEFAULT] CHARACTE ...

  5. 引水入城 2010年NOIP全国联赛提高组(bfs+贪心)

    1066 引水入城 2010年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond     题目描述 Description 在一个遥远 ...

  6. SP1557 GSS2 - Can you answer these queries II(线段树)

    传送门 线段树好题 因为题目中相同的只算一次,我们可以联想到HH的项链,于是考虑离线的做法 先把所有的询问按$r$排序,然后每一次不断将$a[r]$加入线段树 线段树上维护四个值,$sum,hix,s ...

  7. [Swift通天遁地]一、超级工具-(10)使用地图视图MKMapView的相机功能实现创建三维地图

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  8. FFT学习及简单应用(一点点详细)

    什么是FFT 既然打开了这篇博客,大家肯定都已经对FFT(Fast Fourier Transformation)有一点点了解了吧 FFT即为快速傅里叶变换,可以快速求卷积(当然不止这一些应用,但是我 ...

  9. magento getUrl函数跳转admin模块问题

    在用以下代码时,跳转后的url里面会是空的,即没有admin这个值 $this->getUrl('admin/catalog_product/edit', array('id' => $c ...

  10. FCC 基础JavaScript 练习7

    1. Math.random()用来生成一个在0(包括0)到1(不包括1)之间的随机小数,因此Math.random()可能返回0但绝不会返回1. 提示随后的函数都会在return执行前调用,所以我们 ...