前不久把STL细看了一遍,由于看得太“认真”,忘了做笔记,归纳和总结这步漏掉了。于是为了加深印象,打算重看一遍,并记录下来里面的一些实现细节。方便以后能较好的复习它。
以前在项目中运用STL一般都不会涉及到空间配置器,可是,在STL的实现中,空间配置器是重中之重,因为整个STL的操作对象都存放在容器之内,而容器一定需要配置空间以置放资料。所以,在阅读STL源码时,最先需要掌握的就是空间配置器,没了它,容器,算法怎么存在?
C++ STL的空间配置器将内存的配置、释放和对象的构造和析构分开,内存配置操作由alloc::allocate()负责,内存释放由alloc::deallocate()负责;对象构造操作由::construct()负责,对象的析构操作由::destroy()负责。首先放一张思维导图来概述一下STL的整个空间配置器概览。
对象的构造和析构
个人觉得看源码只需要图和代码注释即可,所以本篇博客图片较多!对着图来看代码效率会高很多!
下面是源代码:
#include <new.h> // 需要placement new的原型
// -----------------构造函数---------------------------------//
// 使用placement new在已经分配的内存上构造对象
template <class T1, class T2>
inline void construct(T1* p, const T2& value)
{
new (p) T1(value);//将value设定到指针p所指的空间上
}
// -----------------析构函数---------------------------------//
// -----------第一个版本:接受一个指针--------------------------//
// 调用成员的析构函数, 需要类型具有non-trivial destructor
template <class T>
inline void destroy(T* pointer)
{
pointer->~T();
}
// -----------第二个版本:接受两个迭代器------------------------//
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last)
{
__destroy(first, last, value_type(first));
}
// 首先是两个特化版本
inline void destroy(char*, char*) {}
inline void destroy(wchar_t*, wchar_t*) {}
// 析构一组对象, 用于具有non-trivial destructor
template <class ForwardIterator>
inline void
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
{
for ( ; first < last; ++first)
destroy(&*first);
}
// 如果没有类型non-trivial destructor, 则使用此函数
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}
// 使用traits技术, 判断类型是否就有non-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());
}
内存的配置和释放
在内存配置方面,STL分为两级配置器,当请求的内存大于128b的时候调用第一级配置器,当请求的内存小于等于128b的时候调用第二级配置器。先来看看下面这张表,大概就能知道第一级和第二级配置器主要干了些什么,其他的一些细节如内存池是怎么工作的,下面会给出具体解释。
第一级配置器
首先我们来看第一级配置器的源码:
template <int inst>
class __malloc_alloc_template
{
private:
//调用malloc函数不成功后调用
static void *oom_malloc(size_t);
//调用realloc函数不成功后调用
static void *oom_realloc(void *, size_t);
//类似于C++的set_new_handle错误处理函数一样,如果不设置,在内存不足时,返回THROW_BAD_ALLOC
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
static void (* __malloc_alloc_oom_handler)();
#endif
public:
//直接调用malloc来分配内存