STL allocater 决定两阶段操作区分开来。内存配置操作由 alloc:allocate()负责,内存操作由alloc:deallocate()负责,对象构造操作由::construct()负责,对象析构操作由::destory()负责。
#include<stl_alloc.h>//包含内存空间的配置和释放
#include<stl_construct.h>// 负责 对象内容的构造和析构
构造和析构基本工具:construct()和destroy()
#include <new.h> //要想使用 palcement new 能够在一段内存空间构造对象。
template <class _T1, class _T2>
inline void _Construct(_T1* __p, const _T2& __value) {
new ((void*) __p) _T1(__value); //将value设定到地址p指向的内存上
}
/*
**这叫placenew,在指针p所指向的内存空间创建一个类型为T1的对象。调用的构造函数接受一个类型为const T2&(或其他兼容类型)的参数
new placement
你可以简单的理解为C中的realloc,就是在已有空间的基础上,重新分配一个空间,可以不破坏原来数据,也可以把数据全部用新值覆盖 **
**/
//new一段p指向的内存
template <class _T1>
inline void _Construct(_T1* __p) {
new ((void*) __p) _T1();
}
//以下是destory()第一个版本接受一个指针 调用析构函数 将p所指向的空间析构掉。
template <class _Tp>
inline void _Destroy(_Tp* __pointer) {
__pointer->~_Tp();
}
//以下是destory()第二版本接受两个迭代器此函数设法找出 元素的数值型别,进而利用__type_traits
//求取最合适的措施析构对象。
template <class _ForwardIterator>
inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) {
__destroy(__first, __last, __VALUE_TYPE(__first));
}
//判断元素类型 是否有trivial destructor 有就是 true_type,没有就是false_type
template <class _ForwardIterator, class _Tp>
inline void
__destroy(_ForwardIterator __first, _ForwardIterator __last, _Tp*)
{
typedef typename __type_traits<_Tp>::has_trivial_destructor
_Trivial_destructor;
__destroy_aux(__first, __last, _Trivial_destructor());
}
//如果是 non-trivial destructor 则调用destory第一个版本
template <class _ForwardIterator>
void
__destroy_aux(_ForwardIterator __first, _ForwardIterator __last, __false_type)
{
for ( ; __first != __last; ++__first)
destroy(&*__first);
}
template <class _ForwardIterator>
inline void __destroy_aux(_ForwardIterator, _ForwardIterator, __true_type) {}
----------------------------------------------------------------------
/*
如果用户不定义析构函数,而是用系统自带的,则说明,析构函数基本没有什么用(但默认会被调用)我们称之为trivial destructor。反之,如果特定定义了析构函数,则说明需要在释放空间之前做一些事情,则这个析构函数称为non-trivial destructor。如果某个类中只有基本类型的话是没有必要调用析构函数的,delelte p的时候基本不会产生析构代码。
在STL中空间配置时候destory()函数会判断要释放的迭代器的指向的对象有没有 trivial destructor(STL中有一个 has_trivial_destructor函数,很容易实现检测)放,如果有trivial destructor则什么都不做,如果没有即需要执行一些操作,则执行真正的destory函数。destory()有两个版本,第一个版本接受一个指针,准备将该指针所指之物析构掉,第二个版本接受first和last两个迭代器,准备将[first,last]范围内的所有对象析构掉。我们不知道这个范围有多大,万一很大,而每个对象的析构函数都无关痛痒,那么一次次调用这些析构函数,对效率是一种伤害,因此这里首先利用value_type()获得迭代器所指对象的类别,再利用_type_traits<T>判断该型别的析构函数是否无关痛痒,若是(_true_type),则什么也不做就结束,若否(_false_type),这才以循环的方式巡访整个范围,并在循环中每经历一个对象就调用第一个版本的destory()。
**/
---------------------------------------------------------------------
//以下是destory第二个版本的特化版。
inline void _Destroy(char*, char*) {}
inline void _Destroy(int*, int*) {}
inline void _Destroy(long*, long*) {}
inline void _Destroy(float*, float*) {}
inline void _Destroy(double*, double*) {}
#ifdef __STL_HAS_WCHAR_T
inline void _Destroy(wchar_t*, wchar_t*) {}
#endif /* __STL_HAS_WCHAR_T */
// --------------------------------------------------
// Old names from the HP STL.
__STL_END_NAMESPACE
空间的配置和释放。std::alloc
对象构造前的空间配置和对象构造后的空间释放,由
其设计如下:
(1)向system heap要求空间
(2)考虑多线程状态
(3)考虑内存不足的应变措施
(4)考虑过多小型区块的内存碎片问题
考虑到SGI设计了双层配置器,第一层配置器直接使用malloc()和free(),第二层配置器则视情况超过128bytes 则调用第一级配置器;小于128bytes 便采用复杂的 内存池 整理方式。
第一级配置器 _ _malloc_alloc_template 剖析
// 以下是第一級配置器。
// 注意,無「template型別參數」。「非型別參數」inst完全沒派上用場。
template <int inst>
class __malloc_alloc_template {
private:
static void *oom_malloc(size_t);
static void *oom_realloc(void *, size_t);
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
static void (* __malloc_alloc_oom_handler)();
#endif
public:
static void * allocate(size_t n)
{
void *result = malloc(n); // 第一級配置器直接使用 malloc()
if (0 == result) result = oom_malloc(n);
return result;
}
static void deallocate(void *p, size_t /* n */)
{
free(p); // 第一級配置器直接使用 free()
}
static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
void * result = realloc(p, new_sz); // 第一級配置器直接使用 realloc()
if (0 == result) result = oom_realloc(p, new_sz);
return result;
}
// 以下類似 C++ 的 set_new_handler().
//这个函数的机制是,你可以要求系统在内存配置无法被满足时,调用一个你所指定的函数。 new_handler解决内存不足的特有模式。
static void (* set_malloc_handler(void (*f)()))()
{
void (* old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return(old);
}
};
// malloc_alloc out-of-memory handling
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
template <int inst>
void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;
#endif
template <int inst>
void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
{
void (* my_malloc_handler)();
void *result;
for (;;) { // 不斷嘗試釋放、配置、再釋放、再配置…
my_malloc_handler = __malloc_alloc_oom_handler;
if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
(*my_malloc_handler)(); // 呼叫處理常式,企圖釋放記憶體。
result = malloc(n); // 再次嘗試配置記憶體。
if (result) return(result);
}
}
template <int inst>
void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
{
void (* my_malloc_handler)();
void *result;
for (;;) { // 不斷嘗試釋放、配置、再釋放、再配置…
my_malloc_handler = __malloc_alloc_oom_handler;
if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
(*my_malloc_handler)(); // 呼叫處理常式,企圖釋放記憶體。
result = realloc(p, n); // 再次嘗試配置記憶體。
if (result) return(result);
}
}
typedef __malloc_alloc_template<0> malloc_alloc;