STL源码阅读(四) (SGI STL v3.3)
stl_deque.h (<deque>)
// deque的内存管理,分配一段内存_M_map用来存储指向缓存区域的指针,每当缓存区域buffer不足时,分配一段新的缓存区域,然后
// 将指向该区域的指针添加到_M_map中。buffer大小的分配原则是,当sizeof(_Tp) > 512时,分配的缓存大小sizeof(_Tp);否则,
// 分配的缓存大小为sizeof(_Tp) * (512 / sizeof(_Tp));
template <class _Tp, class _Alloc, bool __is_static>
class _Deque_alloc_base; // 每个类中保留两个分配器对象,_M_map_allocator, _M_node_allocator
template <class _Tp, class _Alloc>
class _Deque_alloc_base<_Tp, _Alloc, true>; // 使用静态内存分配器 {
...
_Tp** _M_map; // 指向缓存结点的指针
size_T _M_map_size; // map的大小
...
}
// deque迭代器,迭代器类型随机迭代器random_access_iterator_tag。
template <class _Tp, class _Ref, class _Ptr>
struct _Deque_iterator {
...
// 迭代器中维护四个指针
_Tp* _M_cur; // 指向当前缓存区域已用空间的最后一个元素
_Tp* _M_first; // 指向当前缓存区域的开始
_Tp* _M_last; // 指向当前缓存区域的末尾
_Map_pointer _M_node; // 指向当前正在使用的那一个缓存区域
...
}
// 注意迭代器迭代元素的方式,迭代器所处理的内存空间从整体上看不是连续的,但从局部看是连续的
// 计算迭代器的差值
difference_type operator-(const _Self& __x) const {
return difference_type(_S_buffer_size()) * (_M_node - __x._M_node - 1) +
(_M_cur - _M_first) + (__x._M_last - __x._M_cur);
}
_Self& operator+=(difference_type __n)
{
difference_type __offset = __n + (_M_cur - _M_first);
if (__offset >= 0 && __offset < difference_type(_S_buffer_size()))
_M_cur += __n;
else {
difference_type __node_offset =
__offset > 0 ? __offset / difference_type(_S_buffer_size())
: -difference_type((-__offset - 1) / _S_buffer_size()) - 1;
_M_set_node(_M_node + __node_offset);
_M_cur = _M_first +
(__offset - __node_offset * difference_type(_S_buffer_size()));
}
return *this;
}
// deque基类
template <class _Tp, class _Alloc>
class _Deque_base
: public _Deque_alloc_base<_Tp,_Alloc, _Alloc_traits<_Tp, _Alloc>::_S_instanceless> {
...
typedef _Deque_iterator<_Tp,_Tp&,_Tp*> iterator;
// 除了从_Deque_alloc_base继承过来的数据成员,还维护两个迭代器,分别指向元素的首部和尾部
iterator _M_first; // 指向第一个元素
iterator _M_finish; // 指向最后一个元素的下一个元素
enum { _S_initial_map_size = 8 }; // _M_map的初始大小为8
...
}
// 初始化__num_elements个节点,最小结点数8个
template <class _Tp, class _Alloc>
void
_Deque_base<_Tp,_Alloc>::_M_initialize_map(size_t __num_elements)
{
size_t __num_nodes =
__num_elements / __deque_buf_size(sizeof(_Tp)) + 1;
_M_map_size = max((size_t) _S_initial_map_size, __num_nodes + 2);
_M_map = _M_allocate_map(_M_map_size); // 当多分配两个结点
// 指向_M_map的最中间,向头部和尾部的扩展能力相同
_Tp** __nstart = _M_map + (_M_map_size - __num_nodes) / 2;
_Tp** __nfinish = __nstart + __num_nodes;
__STL_TRY {
_M_create_nodes(__nstart, __nfinish); // 为每个结点分配内存
}
__STL_UNWIND((_M_deallocate_map(_M_map, _M_map_size),
_M_map = 0, _M_map_size = 0));
_M_start._M_set_node(__nstart);
_M_finish._M_set_node(__nfinish - 1);
_M_start._M_cur = _M_start._M_first;
_M_finish._M_cur = _M_finish._M_first +
__num_elements % __deque_buf_size(sizeof(_Tp));
}
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class deque : protected _Deque_base<_Tp, _Alloc>;
void swap(deque& __x) {
__STD::swap(_M_start, __x._M_start);
__STD::swap(_M_finish, __x._M_finish);
__STD::swap(_M_map, __x._M_map);
__STD::swap(_M_map_size, __x._M_map_size);
}
template <class _Tp, class _Alloc>
void deque<_Tp,_Alloc>::_M_reallocate_map(size_type __nodes_to_add,
bool __add_at_front)
{
size_type __old_num_nodes = _M_finish._M_node - _M_start._M_node + 1;
size_type __new_num_nodes = __old_num_nodes + __nodes_to_add;
_Map_pointer __new_nstart;
if (_M_map_size > 2 * __new_num_nodes) {
__new_nstart = _M_map + (_M_map_size - __new_num_nodes) / 2
+ (__add_at_front ? __nodes_to_add : 0);
if (__new_nstart < _M_start._M_node)
copy(_M_start._M_node, _M_finish._M_node + 1, __new_nstart);
else
copy_backward(_M_start._M_node, _M_finish._M_node + 1,
__new_nstart + __old_num_nodes);
}
else {
size_type __new_map_size =
_M_map_size + max(_M_map_size, __nodes_to_add) + 2;
_Map_pointer __new_map = _M_allocate_map(__new_map_size);
__new_nstart = __new_map + (__new_map_size - __new_num_nodes) / 2
+ (__add_at_front ? __nodes_to_add : 0);
copy(_M_start._M_node, _M_finish._M_node + 1, __new_nstart);
_M_deallocate_map(_M_map, _M_map_size);
_M_map = __new_map;
_M_map_size = __new_map_size;
}
_M_start._M_set_node(__new_nstart);
_M_finish._M_set_node(__new_nstart + __old_num_nodes - 1);
}
参考资料
- sgi STL
- cppreference.com