C++ STL 容器设计实现 -- deque
5、deque
deque 是双端队列(double-ended queue),其实现比较特殊,有多段地址连续的存储空间组成,整理布局如下:
- 每段地址连续内存成为一个 node
- map 是指针构成的数据,每个元素指向一个 node
- start 和 finish 是一个迭代器变量,分别指向第一个和最后一个 node
迭代器以 node 为单位
- cur 指向当前元素
- first 指向 node 第一个元素
- last 指向 node 最后一个元素的下一个地址
- node 指向 map 中相应位置,可以很方便找到前一个或者后一个 node
- node 计算如下
- 元素占用内存小于 512 字节,最大占用 512 字节
- 否则,默认分配一个元素大小的内存
/// stl_deque.h
_GLIBCXX_CONSTEXPR inline size_t
__deque_buf_size(size_t __size)
{ return (__size < _GLIBCXX_DEQUE_BUF_SIZE // 512
? size_t(_GLIBCXX_DEQUE_BUF_SIZE / __size) : size_t(1)); }
5.1、_Deque_iterator
deque 的迭代器是 random access 类型的迭代器,四个成员如上图所示。
/// stl_deque.h
template<typename _Tp, typename _Ref, typename _Ptr>
struct _Deque_iterator
{
#if __cplusplus < 201103L
typedef _Deque_iterator<_Tp, _Tp&, _Tp*> iterator;
typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;
typedef _Tp* _Elt_pointer;
typedef _Tp** _Map_pointer;
#else
private:
template<typename _CvTp>
using __iter = _Deque_iterator<_Tp, _CvTp&, __ptr_rebind<_Ptr, _CvTp>>;
public:
typedef __iter<_Tp> iterator;
typedef __iter<const _Tp> const_iterator;
typedef __ptr_rebind<_Ptr, _Tp> _Elt_pointer;
typedef __ptr_rebind<_Ptr, _Elt_pointer> _Map_pointer;
#endif
static size_t _S_buffer_size() _GLIBCXX_NOEXCEPT
{ return __deque_buf_size(sizeof(_Tp)); }
typedef std::random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Ptr pointer;
typedef _Ref reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef _Deque_iterator _Self;
_Elt_pointer _M_cur;
_Elt_pointer _M_first;
_Elt_pointer _M_last;
_Map_pointer _M_node;
/* ... */
void
_M_set_node(_Map_pointer __new_node) _GLIBCXX_NOEXCEPT
{
_M_node = __new_node;
_M_first = *__new_node;
_M_last = _M_first + difference_type(_S_buffer_size());
}
/* ... */
};
_Deque_iterator 进行 ++ 或者 -- 操作时,当 cur 移动到 last 或回退到 first 时,自动跳转到下一个 node 或者上一个 node
/// stl_deque.h
_Self&
operator++() _GLIBCXX_NOEXCEPT
{
++_M_cur;
if (_M_cur == _M_last) // 进入下一个 node
{
_M_set_node(_M_node + 1);
_M_cur = _M_first;
}
return *this;
}
_Self&
operator--() _GLIBCXX_NOEXCEPT
{
if (_M_cur == _M_first) // 进入上一个 node
{
_M_set_node(_M_node - 1);
_M_cur = _M_last;
}
--_M_cur;
return *this;
}
运算符 += 或者 -= 也是同样的道理。
/// stl_deque.h
_Self&
operator+=(difference_type __n) _GLIBCXX_NOEXCEPT
{
const difference_type __offset = __n + (_M_cur - _M_first);
if (__offset >= 0 && __offset < difference_type(_S_buffer_size()))
_M_cur += __n;
else
{
const 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;
}
_GLIBCXX_NODISCARD
reference
operator[](difference_type __n) const _GLIBCXX_NOEXCEPT
{ return *(*this + __n); }
5.2、_Deque_base::_Deque_impl_data
_Deque_impl_data 封装了 deque 的数据结构 map。
/// stl_deque.h
struct _Deque_impl_data
{
_Map_pointer _M_map;
size_t _M_map_size;
iterator _M_start;
iterator _M_finish;
_Deque_impl_data() _GLIBCXX_NOEXCEPT
: _M_map(), _M_map_size(), _M_start(), _M_finish()
{ }
/* ... */
};
5.3、_Deque_base::_Deque_impl
_Deque_impl 继承 _Deque_impl_data 和 内存分配器 _Tp_alloc_type。采用继承的方法,是避免空类(内存分配器通常没有数据成员)引入内存消耗。
/// stl_deque.h
// This struct encapsulates the implementation of the std::deque
// standard container and at the same time makes use of the EBO
// for empty allocators.
struct _Deque_impl
: public _Tp_alloc_type, public _Deque_impl_data
{
/* ... */
};
5.4、_Deque_base
_Deque_base 只有一个 _Deque_impl 成员变量,_Deque_base 另外负责 node 和 map 的内存分配与释放。
/// stl_deque.h
template<typename _Tp, typename _Alloc>
class _Deque_base
{
protected:
typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
rebind<_Tp>::other _Tp_alloc_type;
typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Alloc_traits;
typedef typename _Alloc_traits::pointer _Ptr;
typedef typename _Alloc_traits::const_pointer _Ptr_const;
typedef typename _Alloc_traits::template rebind<_Ptr>::other
_Map_alloc_type;
typedef __gnu_cxx::__alloc_traits<_Map_alloc_type> _Map_alloc_traits;
typedef _Alloc allocator_type;
allocator_type
get_allocator() const _GLIBCXX_NOEXCEPT
{ return allocator_type(_M_get_Tp_allocator()); }
typedef _Deque_iterator<_Tp, _Tp&, _Ptr> iterator;
typedef _Deque_iterator<_Tp, const _Tp&, _Ptr_const> const_iterator;
/* ... */
typedef typename iterator::_Map_pointer _Map_pointer;
/* ... */
enum { _S_initial_map_size = 8 };
_Deque_impl _M_impl;
};
成员函数 _M_allocate_node() 和 _M_deallocate_node() 用于分配和释放一个 node 内存。
/// stl_deque.h
_Ptr
_M_allocate_node()
{
typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Traits;
return _Traits::allocate(_M_impl, __deque_buf_size(sizeof(_Tp)));
}
void
_M_deallocate_node(_Ptr __p) _GLIBCXX_NOEXCEPT
{
typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Traits;
_Traits::deallocate(_M_impl, __p, __deque_buf_size(sizeof(_Tp)));
}
_M_create_nodes() 和 _M_destroy_nodes() 分别调用 _M_allocate_node() 和 _M_deallocate_node() 函数,用于申请或者释放多个 node 的内存。
/// stl_deque.h
template<typename _Tp, typename _Alloc>
void
_Deque_base<_Tp, _Alloc>::
_M_create_nodes(_Map_pointer __nstart, _Map_pointer __nfinish)
{
_Map_pointer __cur;
__try
{
for (__cur = __nstart; __cur < __nfinish; ++__cur)
*__cur = this->_M_allocate_node();
}
__catch(...)
{
_M_destroy_nodes(__nstart, __cur);
__throw_exception_again;
}
}
template<typename _Tp, typename _Alloc>
void
_Deque_base<_Tp, _Alloc>::
_M_destroy_nodes(_Map_pointer __nstart,
_Map_pointer __nfinish) _GLIBCXX_NOEXCEPT
{
for (_Map_pointer __n = __nstart; __n < __nfinish; ++__n)
_M_deallocate_node(*__n);
}
成员函数 _M_allocate_map() 和 _M_deallocate_map() 用于分配和释放 map 的内存。
/// stl_deque.h
_Map_pointer
_M_allocate_map(size_t __n)
{
_Map_alloc_type __map_alloc = _M_get_map_allocator();
return _Map_alloc_traits::allocate(__map_alloc, __n);
}
void
_M_deallocate_map(_Map_pointer __p, size_t __n) _GLIBCXX_NOEXCEPT
{
_Map_alloc_type __map_alloc = _M_get_map_allocator();
_Map_alloc_traits::deallocate(__map_alloc, __p, __n);
}
_M_initialize_map() 函数用于初始化 map,包括申请 node 内存。
- 1)计算 node 个数
- 2)申请 map 内存(至少额外申请 2 个空间,用于应对未来的元素插入)
- 3)申请 node
- 4)初始化 _Deque_impl_data 成员变量
/// deque.tcc
template<typename _Tp, typename _Alloc>
void
_Deque_base<_Tp, _Alloc>::
_M_initialize_map(size_t __num_elements)
{
const size_t __num_nodes = (__num_elements / __deque_buf_size(sizeof(_Tp))
+ 1);
this->_M_impl._M_map_size = std::max((size_t) _S_initial_map_size,
size_t(__num_nodes + 2)); // 2 个额外空间
this->_M_impl._M_map = _M_allocate_map(this->_M_impl._M_map_size);
// For "small" maps (needing less than _M_map_size nodes), allocation
// starts in the middle elements and grows outwards. So nstart may be
// the beginning of _M_map, but for small maps it may be as far in as
// _M_map+3.
_Map_pointer __nstart = (this->_M_impl._M_map
+ (this->_M_impl._M_map_size - __num_nodes) / 2);
_Map_pointer __nfinish = __nstart + __num_nodes;
__try
{ _M_create_nodes(__nstart, __nfinish); }
__catch(...)
{
_M_deallocate_map(this->_M_impl._M_map, this->_M_impl._M_map_size);
this->_M_impl._M_map = _Map_pointer();
this->_M_impl._M_map_size = 0;
__throw_exception_again;
}
this->_M_impl._M_start._M_set_node(__nstart);
this->_M_impl._M_finish._M_set_node(__nfinish - 1);
this->_M_impl._M_start._M_cur = _M_impl._M_start._M_first;
this->_M_impl._M_finish._M_cur = (this->_M_impl._M_finish._M_first
+ __num_elements
% __deque_buf_size(sizeof(_Tp))); // 最后一个元素下一个位置
}
5.5、std::deque
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class deque : protected _Deque_base<_Tp, _Alloc>
{
typedef _Deque_base<_Tp, _Alloc> _Base;
typedef typename _Base::_Tp_alloc_type _Tp_alloc_type;
typedef typename _Base::_Alloc_traits _Alloc_traits;
typedef typename _Base::_Map_pointer _Map_pointer;
public:
typedef _Tp value_type;
typedef typename _Alloc_traits::pointer pointer;
typedef typename _Alloc_traits::const_pointer const_pointer;
typedef typename _Alloc_traits::reference reference;
typedef typename _Alloc_traits::const_reference const_reference;
typedef typename _Base::iterator iterator;
typedef typename _Base::const_iterator const_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef _Alloc allocator_type;
/* ... */
};
deque 重点分析插入元素的几个成员函数,push_back/front,pop_back/front,insert。
5.5.1、push_back/front
如果预留有空间,直接插入,否则需要申请 node 或者重新扩展 map。push_back() 和 push_front() 分别调用 _M_push_back_aux() 和 _M_push_front_aux() 用于处理预留空间消耗完的情况。
/// stl_deque.h
void
push_back(const value_type& __x)
{
if (this->_M_impl._M_finish._M_cur
!= this->_M_impl._M_finish._M_last - 1)
{ // 直接插入
_Alloc_traits::construct(this->_M_impl,
this->_M_impl._M_finish._M_cur, __x);
++this->_M_impl._M_finish._M_cur;
}
else
_M_push_back_aux(__x);
}
void
push_front(const value_type& __x)
{
if (this->_M_impl._M_start._M_cur != this->_M_impl._M_start._M_first)
{ // 直接插入
_Alloc_traits::construct(this->_M_impl,
this->_M_impl._M_start._M_cur - 1,
__x);
--this->_M_impl._M_start._M_cur;
}
else
_M_push_front_aux(__x);
}
_M_push_back_aux() 和 _M_push_front_aux() 两个函数原理相同,首先判断是否需要拓展 map,必要时先拓展 map,然后申请一个 node,最后插入新增元素。
/// deque.tcc
template<typename _Tp, typename _Alloc>
#if __cplusplus >= 201103L
template<typename... _Args>
void
deque<_Tp, _Alloc>::
_M_push_back_aux(_Args&&... __args)
#else
/* ... */
#endif
{
if (size() == max_size())
__throw_length_error(
__N("cannot create std::deque larger than max_size()"));
_M_reserve_map_at_back(); // 必要时拓展 map
*(this->_M_impl._M_finish._M_node + 1) = this->_M_allocate_node(); // 申请 node
__try
{
#if __cplusplus >= 201103L
_Alloc_traits::construct(this->_M_impl,
this->_M_impl._M_finish._M_cur,
std::forward<_Args>(__args)...); // 插入元素
#else
/* ... */
#endif
this->_M_impl._M_finish._M_set_node(this->_M_impl._M_finish._M_node
+ 1);
this->_M_impl._M_finish._M_cur = this->_M_impl._M_finish._M_first;
}
__catch(...)
{
_M_deallocate_node(*(this->_M_impl._M_finish._M_node + 1));
__throw_exception_again;
}
}
// Called only if _M_impl._M_start._M_cur == _M_impl._M_start._M_first.
template<typename _Tp, typename _Alloc>
#if __cplusplus >= 201103L
template<typename... _Args>
void
deque<_Tp, _Alloc>::
_M_push_front_aux(_Args&&... __args)
#else
/* ... */
#endif
{
if (size() == max_size())
__throw_length_error(
__N("cannot create std::deque larger than max_size()"));
_M_reserve_map_at_front(); // 必要时拓展 map
*(this->_M_impl._M_start._M_node - 1) = this->_M_allocate_node();
__try
{
this->_M_impl._M_start._M_set_node(this->_M_impl._M_start._M_node
- 1);
this->_M_impl._M_start._M_cur = this->_M_impl._M_start._M_last - 1;
#if __cplusplus >= 201103L
_Alloc_traits::construct(this->_M_impl,
this->_M_impl._M_start._M_cur,
std::forward<_Args>(__args)...); // 插入元素
#else
/* ... */
#endif
}
__catch(...)
{
++this->_M_impl._M_start;
_M_deallocate_node(*(this->_M_impl._M_start._M_node - 1));
__throw_exception_again;
}
}
_M_reserve_map_at_back() 和 _M_reserve_map_at_front() 都调用 _M_reallocate_map() 函数拓展 map。
/// deque.tcc
void
_M_reserve_map_at_back(size_type __nodes_to_add = 1)
{
if (__nodes_to_add + 1 > this->_M_impl._M_map_size
- (this->_M_impl._M_finish._M_node - this->_M_impl._M_map))
_M_reallocate_map(__nodes_to_add, false);
}
void
_M_reserve_map_at_front(size_type __nodes_to_add = 1)
{
if (__nodes_to_add > size_type(this->_M_impl._M_start._M_node
- this->_M_impl._M_map))
_M_reallocate_map(__nodes_to_add, true);
}
_M_reallocate_map() 函数定义如下,如果 map 预留的空间足够大(2 倍),不需要拓展 map,只需要移动 nodes 就可以了,否则旧重新申请一个 map,新 map 的大小至少是原来的两倍 + 2。
/// deque.tcc
template <typename _Tp, typename _Alloc>
void
deque<_Tp, _Alloc>::
_M_reallocate_map(size_type __nodes_to_add, bool __add_at_front)
{
const size_type __old_num_nodes
= this->_M_impl._M_finish._M_node - this->_M_impl._M_start._M_node + 1;
const size_type __new_num_nodes = __old_num_nodes + __nodes_to_add;
_Map_pointer __new_nstart;
if (this->_M_impl._M_map_size > 2 * __new_num_nodes)
{ // 不需要拓展 map,只需要移动 nodes
__new_nstart = this->_M_impl._M_map + (this->_M_impl._M_map_size
- __new_num_nodes) / 2
+ (__add_at_front ? __nodes_to_add : 0);
if (__new_nstart < this->_M_impl._M_start._M_node)
std::copy(this->_M_impl._M_start._M_node,
this->_M_impl._M_finish._M_node + 1,
__new_nstart);
else
std::copy_backward(this->_M_impl._M_start._M_node,
this->_M_impl._M_finish._M_node + 1,
__new_nstart + __old_num_nodes);
}
else
{ // 拓展 map
size_type __new_map_size = this->_M_impl._M_map_size
+ std::max(this->_M_impl._M_map_size,
__nodes_to_add) + 2; // 新 map 的大小
// 申请新 map
_Map_pointer __new_map = this->_M_allocate_map(__new_map_size);
__new_nstart = __new_map + (__new_map_size - __new_num_nodes) / 2
+ (__add_at_front ? __nodes_to_add : 0);
std::copy(this->_M_impl._M_start._M_node,
this->_M_impl._M_finish._M_node + 1,
__new_nstart); // 释放原来 map
_M_deallocate_map(this->_M_impl._M_map, this->_M_impl._M_map_size);
this->_M_impl._M_map = __new_map;
this->_M_impl._M_map_size = __new_map_size;
}
this->_M_impl._M_start._M_set_node(__new_nstart);
this->_M_impl._M_finish._M_set_node(__new_nstart + __old_num_nodes - 1);
}
5.5.2、pop_back/front
相对于 push_back/front,pop_back/front 就比较简单,只需要考虑 node 的释放,不需要对 map 进行收缩。
/// stl_deque.h
void
pop_back() _GLIBCXX_NOEXCEPT
{
__glibcxx_requires_nonempty();
if (this->_M_impl._M_finish._M_cur
!= this->_M_impl._M_finish._M_first)
{ // 在 [_M_first, _M_cur) 中
--this->_M_impl._M_finish._M_cur;
_Alloc_traits::destroy(_M_get_Tp_allocator(),
this->_M_impl._M_finish._M_cur);
}
else
_M_pop_back_aux();
}
void
pop_front() _GLIBCXX_NOEXCEPT
{
__glibcxx_requires_nonempty();
if (this->_M_impl._M_start._M_cur
!= this->_M_impl._M_start._M_last - 1)
{ // 在 [_M_cur, _M_last) 中
_Alloc_traits::destroy(_M_get_Tp_allocator(),
this->_M_impl._M_start._M_cur);
++this->_M_impl._M_start._M_cur;
}
else
_M_pop_front_aux();
}
_M_pop_back_aux() 和 _M_pop_front_aux() 也比较简单
/// deque.tcc
template <typename _Tp, typename _Alloc>
void deque<_Tp, _Alloc>::
_M_pop_back_aux()
{
_M_deallocate_node(this->_M_impl._M_finish._M_first); // 释放 node
this->_M_impl._M_finish._M_set_node(this->_M_impl._M_finish._M_node - 1);
this->_M_impl._M_finish._M_cur = this->_M_impl._M_finish._M_last - 1;
_Alloc_traits::destroy(_M_get_Tp_allocator(),
this->_M_impl._M_finish._M_cur); // 析构元素
}
template <typename _Tp, typename _Alloc>
void deque<_Tp, _Alloc>::
_M_pop_front_aux()
{
_Alloc_traits::destroy(_M_get_Tp_allocator(),
this->_M_impl._M_start._M_cur); // 析构元素
_M_deallocate_node(this->_M_impl._M_start._M_first);
this->_M_impl._M_start._M_set_node(this->_M_impl._M_start._M_node + 1); // 释放 node
this->_M_impl._M_start._M_cur = this->_M_impl._M_start._M_first;
}
5.5.3、insert
deque 支持在任意位置插入元素,insert() 的实现比较复杂。
首先是插入单个元素,比如 insert(pos, val)
- 插入位置在 begin(),调用 push_front() 函数插入
- 插入位置在 end(),调用 push_end() 函数插入
- 调用 _M_insert_aux() 函数处理
/// deque.tcc
template <typename _Tp, typename _Alloc>
typename deque<_Tp, _Alloc>::iterator
deque<_Tp, _Alloc>::
#if __cplusplus >= 201103L
insert(const_iterator __position, const value_type& __x)
#else
/* ... */
#endif
{
if (__position._M_cur == this->_M_impl._M_start._M_cur)
{ // 插入位置在 begin()
push_front(__x);
return this->_M_impl._M_start;
}
else if (__position._M_cur == this->_M_impl._M_finish._M_cur)
{ // 插入位置在 end()
push_back(__x);
iterator __tmp = this->_M_impl._M_finish;
--__tmp;
return __tmp;
}
else
return _M_insert_aux(__position._M_const_cast(), __x);
}
_M_insert_aux() 先移动元素,腾出插入位置,然后插入元素。
/// deque.tcc
template<typename _Tp, typename _Alloc>
#if __cplusplus >= 201103L
template<typename... _Args>
typename deque<_Tp, _Alloc>::iterator
deque<_Tp, _Alloc>::
_M_insert_aux(iterator __pos, _Args&&... __args)
{
value_type __x_copy(std::forward<_Args>(__args)...); // XXX copy
#else
/* ... */
#endif
difference_type __index = __pos - this->_M_impl._M_start;
if (static_cast<size_type>(__index) < size() / 2)
{ // 移动前半部
push_front(_GLIBCXX_MOVE(front())); // 赋值第一个元素
iterator __front1 = this->_M_impl._M_start;
++__front1;
iterator __front2 = __front1;
++__front2;
__pos = this->_M_impl._M_start + __index;
iterator __pos1 = __pos;
++__pos1; // 将 [front2, pos1) 元素移动到 [front1, )
_GLIBCXX_MOVE3(__front2, __pos1, __front1);
}
else
{ // 移动后半部
push_back(_GLIBCXX_MOVE(back()));
iterator __back1 = this->_M_impl._M_finish;
--__back1;
iterator __back2 = __back1;
--__back2;
__pos = this->_M_impl._M_start + __index;
_GLIBCXX_MOVE_BACKWARD3(__pos, __back2, __back1);
}
*__pos = _GLIBCXX_MOVE(__x_copy);
return __pos;
}
然后插入多个相同的值,比如 insert(pos, n, val)
/// stl_deque.h
iterator
insert(const_iterator __position, size_type __n, const value_type& __x)
{
difference_type __offset = __position - cbegin();
_M_fill_insert(__position._M_const_cast(), __n, __x);
return begin() + __offset;
}
_M_fill_insert() 处理逻辑是
- 插入位置在 begin(),在 begin() 插入 n 个元素
- 插入位置在 end(),在 end() 后面插入 n 个元素
- 调用 _M_insert_aux() 处理,先整体移动出 n 个位置的空间,再插入
/// deque.tcc
template <typename _Tp, typename _Alloc>
void
deque<_Tp, _Alloc>::
_M_fill_insert(iterator __pos, size_type __n, const value_type& __x)
{
if (__pos._M_cur == this->_M_impl._M_start._M_cur)
{ // 插入位置在 begin(),先申请空间,在赋值
iterator __new_start = _M_reserve_elements_at_front(__n);
__try
{
std::__uninitialized_fill_a(__new_start, this->_M_impl._M_start,
__x, _M_get_Tp_allocator());
this->_M_impl._M_start = __new_start;
}
__catch(...)
{
_M_destroy_nodes(__new_start._M_node,
this->_M_impl._M_start._M_node);
__throw_exception_again;
}
}
else if (__pos._M_cur == this->_M_impl._M_finish._M_cur)
{ // 插入位置在 end()
iterator __new_finish = _M_reserve_elements_at_back(__n);
__try
{
std::__uninitialized_fill_a(this->_M_impl._M_finish,
__new_finish, __x,
_M_get_Tp_allocator());
this->_M_impl._M_finish = __new_finish;
}
__catch(...)
{
_M_destroy_nodes(this->_M_impl._M_finish._M_node + 1,
__new_finish._M_node + 1);
__throw_exception_again;
}
}
else
_M_insert_aux(__pos, __n, __x);
}
_M_insert_aux() 定义如下,根据插入位置,决定移动较少部分元素,腾出 n 个元素的空间。
/// deque.tcc
template <typename _Tp, typename _Alloc>
void
deque<_Tp, _Alloc>::
_M_insert_aux(iterator __pos, size_type __n, const value_type& __x)
{
const difference_type __elems_before = __pos - this->_M_impl._M_start;
const size_type __length = this->size();
value_type __x_copy = __x;
if (__elems_before < difference_type(__length / 2))
{ // 移动前半部
iterator __new_start = _M_reserve_elements_at_front(__n);
iterator __old_start = this->_M_impl._M_start;
__pos = this->_M_impl._M_start + __elems_before;
__try
{
if (__elems_before >= difference_type(__n))
{
iterator __start_n = (this->_M_impl._M_start
+ difference_type(__n));
std::__uninitialized_move_a(this->_M_impl._M_start,
__start_n, __new_start,
_M_get_Tp_allocator());
this->_M_impl._M_start = __new_start;
_GLIBCXX_MOVE3(__start_n, __pos, __old_start);
std::fill(__pos - difference_type(__n), __pos, __x_copy);
}
else
{
std::__uninitialized_move_fill(this->_M_impl._M_start,
__pos, __new_start,
this->_M_impl._M_start,
__x_copy,
_M_get_Tp_allocator());
this->_M_impl._M_start = __new_start;
std::fill(__old_start, __pos, __x_copy);
}
}
__catch(...)
{
_M_destroy_nodes(__new_start._M_node,
this->_M_impl._M_start._M_node);
__throw_exception_again;
}
}
else
{ // 移动后半部
iterator __new_finish = _M_reserve_elements_at_back(__n);
iterator __old_finish = this->_M_impl._M_finish;
const difference_type __elems_after =
difference_type(__length) - __elems_before;
__pos = this->_M_impl._M_finish - __elems_after;
__try
{
if (__elems_after > difference_type(__n))
{
iterator __finish_n = (this->_M_impl._M_finish
- difference_type(__n));
std::__uninitialized_move_a(__finish_n,
this->_M_impl._M_finish,
this->_M_impl._M_finish,
_M_get_Tp_allocator());
this->_M_impl._M_finish = __new_finish;
_GLIBCXX_MOVE_BACKWARD3(__pos, __finish_n, __old_finish);
std::fill(__pos, __pos + difference_type(__n), __x_copy);
}
else
{
std::__uninitialized_fill_move(this->_M_impl._M_finish,
__pos + difference_type(__n),
__x_copy, __pos,
this->_M_impl._M_finish,
_M_get_Tp_allocator());
this->_M_impl._M_finish = __new_finish;
std::fill(__pos, __old_finish, __x_copy);
}
}
__catch(...)
{
_M_destroy_nodes(this->_M_impl._M_finish._M_node + 1,
__new_finish._M_node + 1);
__throw_exception_again;
}
}
}
最后一种是插入迭代器指向的区间元素,比如 insert(pos, begin, end)
/// stl_deque.h
template<typename _InputIterator,
typename = std::_RequireInputIter<_InputIterator>>
iterator
insert(const_iterator __position, _InputIterator __first,
_InputIterator __last)
{
difference_type __offset = __position - cbegin();
_M_range_insert_aux(__position._M_const_cast(), __first, __last,
std::__iterator_category(__first));
return begin() + __offset;
}
_M_range_insert_aux() 需要区分迭代器类型,如果是 input_iterator_tag,调用 std::copy() 单个元素进行插入。否则处理方式和 _M_fill_insert() 函数类似。
/// deque.tcc
template <typename _Tp, typename _Alloc>
template <typename _InputIterator>
void
deque<_Tp, _Alloc>::
_M_range_insert_aux(iterator __pos,
_InputIterator __first, _InputIterator __last,
std::input_iterator_tag)
{ std::copy(__first, __last, std::inserter(*this, __pos)); }
template <typename _Tp, typename _Alloc>
template <typename _ForwardIterator>
void
deque<_Tp, _Alloc>::
_M_range_insert_aux(iterator __pos,
_ForwardIterator __first, _ForwardIterator __last,
std::forward_iterator_tag)
{
const size_type __n = std::distance(__first, __last);
if (__pos._M_cur == this->_M_impl._M_start._M_cur)
{
iterator __new_start = _M_reserve_elements_at_front(__n);
__try
{
std::__uninitialized_copy_a(__first, __last, __new_start,
_M_get_Tp_allocator());
this->_M_impl._M_start = __new_start;
}
__catch(...)
{
_M_destroy_nodes(__new_start._M_node,
this->_M_impl._M_start._M_node);
__throw_exception_again;
}
}
else if (__pos._M_cur == this->_M_impl._M_finish._M_cur)
{
iterator __new_finish = _M_reserve_elements_at_back(__n);
__try
{
std::__uninitialized_copy_a(__first, __last,
this->_M_impl._M_finish,
_M_get_Tp_allocator());
this->_M_impl._M_finish = __new_finish;
}
__catch(...)
{
_M_destroy_nodes(this->_M_impl._M_finish._M_node + 1,
__new_finish._M_node + 1);
__throw_exception_again;
}
}
else
_M_insert_aux(__pos, __first, __last, __n);
}
_M_insert_aux() 函数处理方法类似,根据插入位置,决定移动较少部分元素,腾出 n 个元素的空间,然后将 [first, last) 拷贝 n 个元素到 deque。
欢迎关注公众号“源知源为”,阅读更多技术干货
#STL#C/C++ 语言基础

