提前声明:这个文章本来应该命名为空间配置器(一)的,也就是说,这篇文章应该诞生于上篇文章 之前的,然而,由于本人的原因,造成这样的失误。
最近一直在读《STL源码剖析》的第2章节,在讲述空间配置器的外部接口的时候,并不是特别清楚,反倒是把两级空间配置器的底层实现细节搞得比较清晰,所以,上一篇文章先于本篇文章。这两天,仔细阅读了接口这一部分,然后加上对自己空间配置器的使用,决定再来整理此文。
1.空间配置器的外部接口:
在上一篇文章中,我们知道,大于128字节的,就调用一级空间配置器,小于128字节的就调用二级空间配置器,
整个设计究竟只开放一级空间配置器还是同时开放二级空间配置器,取决于__USE_MALLOC是否被定义,如果定义了,就调用一级空间配置器,如果没有定义,就调用二级空间配置器(中间有可能去调到一级空间配置器)。SGI STL并未定义
__USE_MALLOC。(引至《STL源码剖析》侯捷著)
所以,无论如何,中间都有可能去调到malloc()函数。
也就是说,默认调用二级空间配置器,如果大于128字节,才去调用一级空间配置器。
下边给出一级空间配置器和二级空间配置器的外部包装接口:(注明:截取至《STL源码剖析》侯捷著)
这样对两级空间配置器的外部接口也是比较清楚了。
我们需要在Alloc.h的文件中补充外部接口:
#ifdef __USE_MALLOC
typedef __MallocAllocTemplate<0> Alloc;
#else
typedef __DefaultAllocTemplate<false,0> Alloc;
#endif//__USE_MALLOC
template<typename T,typename _Alloc = Alloc>
class SimpleAlloc
{
public:
static T* Allocate(size_t n)
{
return (T*)(_Alloc::Allocate(n * sizeof(T)));
}
static T* Allocate()
{
return (T*)(_Alloc::Allocate(sizeof(T)));
}
static void Deallocate(T* ptr,size_t n)
{
_Alloc::Deallocate(ptr,n * sizeof(T));
}
static void Deallocate(T* ptr)
{
_Alloc::Deallocate(ptr,sizeof(T));
}
};
2.空间配置器的使用
在上篇文章,我们使用trace跟踪来测试空间配置器的,这里,我们自己模拟实现一个容器list,然后使用自己的空间配置器。
//list.h文件
#pragma once
#include"Alloc.h"
#include"Construct.h"
template<typename T>
struct ListNode
{
T _data;
ListNode<T>* _prev;
ListNode<T>* _next;
ListNode(const T& x = T())
:_data(x)
,_prev(NULL)
,_next(NULL)
{}
};
template<typename T,typename Ref,typename Ptr>
struct ListIterator
{
typedef ListIterator<T,T&,T*> Self;
typedef ListNode<T> Node;
Node* _node;
ListIterator(Node* p)
:_node(p)
{}
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self operator++(int)
{
Node* tmp = _node;
_node = _node->_next;
return tmp;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator--(int)
{
Node* tmp = _node;
_node = _node->_prev;
return tmp;
}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &(operator*());
}
bool operator != (const Self& s) const
{
return _node != s._node;
}
bool operator == (const Self& s) const
{
return !(*this != s);
}
};
template<typename T,typename _Alloc = Alloc>
class List
{
typedef ListNode<T> Node;
typedef SimpleAlloc<Node, _Alloc> ListNodeAllocator;
public:
typedef ListIterator<T,T&,T*> Iterator;
typedef ListIterator<T,const T&,const T*> ConstIterator;
List()
:_head(NULL)
{
_head = BuyNode(T());
_head->_next = _head;
_head->_prev = _head;
}
~List()
{
Clear();
DestroyNode(_head);
}
void Clear()
{
Iterator it = Begin();
while(it != End())
{
Node* del = it._node;
++it;
DestroyNode(del);
}
_head->_prev = _head;
_head->_next = _head;
}
void Insert(Iterator pos,const T& x)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* tmp = BuyNode(x);
tmp->_next = cur;
prev->_next = tmp;
tmp->_prev = prev;
cur->_prev = tmp;
}
void Erase(Iterator pos)
{
Node* del = pos._node;
Node* prev = del->_prev;
Node* next = del->_next;
prev->_next = next;
next->_prev = prev;
}
Iterator Begin()
{
return _head->_next;
}
ConstIterator Begin() const
{
return _head->_next;
}
Iterator End()
{
return _head;
}
ConstIterator End() const
{
return _head;
}
void PushBack(const T& x)
{
Insert(Iterator(_head),x);
}
protected:
Node* BuyNode(const T& x)
{
Node* node = ListNodeAllocator::Allocate();
Construct(node,x);
return node;
}
void DestroyNode(Node* ptr)
{
Destory(ptr);
ListNodeAllocator::Deallocate(ptr);
}
private:
Node* _head;
};
//construct.h文件
#pragma once
template<class T1, class T2>
inline void Construct(T1* p, T2 value)
{
new(p) T1(value);
}
template<class T>
inline void Destory(T* p)
{
p->~T();
}