deque概述<stl源码剖析>
vector是单向开口的连续线性空间,deque则是双向开口的连续线性空间。双向开口,意思是可以在头尾两端分别做元素的插入和删除操作。 deque和vector最大的差异,在于deque允许于常数时间内对头端进行元素的插入或移除操作 ,二在于deque没有所谓的容量概念,因为它是动态的以分段连续的空间组合而成,随时可以增加一段新的空间并链接起来 。 像vector那样"因旧空间不足而重新配置一块更大空间,然后复制元素,在释放旧空间",这样的事情在deque是不会发生的 因为deque的迭代器为了提供 random access iterator,相对vector很复杂。因此,除非必要,我们应尽可能的选择vector而非deque,对deque进行的排序工作,为了最高效率,可将deque先完整复制到一个vector身上,对vector排序后(STL sort算法),再复制回deque。
示意图
__deque_iterator
inline size_t __deque_buf_size ( size_t n, size_t sz)
{
return n != 0 ? n : ( sz < 512 ? size_t ( 512 / sz) : size_t ( 1 ) ) ;
}
template < class T , class Ref , class Ptr >
struct __deque_iterator {
typedef __deque_iterator< T, T& , T* > iterator;
typedef __deque_iterator< T, const T& , const T* > const_iterator;
static size_t buffer_size ( ) { return __deque_buf_size ( 0 , sizeof ( T) ) ; }
#endif
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* * map_pointer;
typedef __deque_iterator self;
T* cur;
T* first;
T* last;
map_pointer node;
void set_node ( map_pointer new_node) {
node = new_node;
first = * new_node;
last = first + difference_type ( buffer_size ( ) ) ;
}
reference operator * ( ) const { return * cur; }
self& operator ++ ( ) {
++ cur;
if ( cur == last) {
set_node ( node + 1 ) ;
cur = first;
}
return * this ;
}
self operator ++ ( int ) {
self tmp = * this ;
++ * this ;
return tmp;
}
self& operator -- ( ) {
if ( cur == first) {
set_node ( node - 1 ) ;
cur = last;
}
-- cur;
return * this ;
}
self& operator + = ( difference_type n) {
difference_type offset = n + ( cur - first) ;
if ( offset >= 0 && offset < difference_type ( buffer_size ( ) ) )
cur + = n;
else {
difference_type node_offset =
offset > 0 ? offset / difference_type ( buffer_size ( ) )
: - difference_type ( ( - offset - 1 ) / buffer_size ( ) ) - 1 ;
set_node ( node + node_offset) ;
cur = first + ( offset - node_offset * difference_type ( buffer_size ( ) ) ) ;
}
return * this ;
}
self operator + ( difference_type n) const {
self tmp = * this ;
return tmp + = n;
}
self& operator - = ( difference_type n) { return * this + = - n; }
self operator - ( difference_type n) const {
self tmp = * this ;
return tmp - = n;
}
}
容器deque
template < class T , class Alloc = alloc, size_t BufSiz = 0 >
class deque {
public :
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
public :
#ifndef __STL_NON_TYPE_TMPL_PARAM_BUG
typedef __deque_iterator< T, T& , T* , BufSiz> iterator;
typedef __deque_iterator< T, const T& , const T& , BufSiz> const_iterator;
#else
typedef __deque_iterator< T, T& , T* > iterator;
typedef __deque_iterator< T, const T& , const T* > const_iterator;
#endif
protected :
typedef pointer* map_pointer;
typedef simple_alloc< value_type, Alloc> data_allocator;
typedef simple_alloc< pointer, Alloc> map_allocator;
static size_type buffer_size ( ) {
return __deque_buf_size ( BufSiz, sizeof ( value_type) ) ;
}
static size_type initial_map_size ( ) { return 8 ; }
protected :
iterator start;
iterator finish;
map_pointer map;
size_type map_size;
public :
deque ( )
: start ( ) , finish ( ) , map ( 0 ) , map_size ( 0 )
{
create_map_and_nodes ( 0 ) ;
}
static size_type initial_map_size ( ) { return 8 ; }
template < class T , class Alloc , size_t BufSize>
void deque< T, Alloc, BufSize> :: create_map_and_nodes ( size_type num_elements) {
size_type num_nodes = num_elements / buffer_size ( ) + 1 ;
map_size = max ( initial_map_size ( ) , num_nodes + 2 ) ;
map = map_allocator:: allocate ( map_size) ;
map_pointer nstart = map + ( map_size - num_nodes) / 2 ;
map_pointer nfinish = nstart + num_nodes - 1 ;
map_pointer cur;
__STL_TRY{
for ( cur = nstart; cur <= nfinish; ++ cur)
* cur = allocate_node ( ) ;
}
catch ( . . . ) {
for ( map_pointer n = nstart; n < cur; ++ n)
deallocate_node ( * n) ;
map_allocator:: deallocate ( map, map_size) ;
throw ;
}
start. set_node ( nstart) ;
finish. set_node ( nfinish) ;
start. cur = start. first;
finish. cur = finish. first + num_elements % buffer_size ( ) ;
}
public :
iterator begin ( ) { return start; }
iterator end ( ) { return finish; }
reference front ( ) { return * start; }
reference back ( ) {
iterator tmp = finish;
-- tmp;
return * tmp;
}
pointer allocate_node ( ) { return data_allocator:: allocate ( buffer_size ( ) ) ; }
template < class T , class Alloc , size_t BufSize>
void deque< T, Alloc, BufSize> :: push_back_aux ( const value_type& t) {
value_type t_copy = t;
reserve_map_at_back ( ) ;
* ( finish. node + 1 ) = allocate_node ( ) ;
__STL_TRY{
construct ( finish. cur, t_copy) ;
finish. set_node ( finish. node + 1 ) ;
finish. cur = finish. first;
}
__STL_UNWIND ( deallocate_node ( * ( finish. node + 1 ) ) ) ;
}
void push_back ( const value_type& t) {
if ( finish. cur != finish. last - 1 ) {
construct ( finish. cur, t) ;
++ finish. cur;
}
else
push_back_aux ( t) ;
}
template < class T , class Alloc , size_t BufSize>
void deque< T, Alloc, BufSize> :: reallocate_map ( size_type nodes_to_add,
bool add_at_front) {
size_type old_num_nodes = finish. node - start. node + 1 ;
size_type new_num_nodes = old_num_nodes + nodes_to_add;
map_pointer new_nstart;
if ( map_size > 2 * new_num_nodes) {
new_nstart = map + ( map_size - new_num_nodes) / 2
+ ( add_at_front ? nodes_to_add : 0 ) ;
if ( new_nstart < start. node)
copy ( start. node, finish. node + 1 , new_nstart) ;
else
copy_backward ( start. node, finish. node + 1 , new_nstart + old_num_nodes) ;
}
else {
size_type new_map_size = map_size + max ( map_size, nodes_to_add) + 2 ;
map_pointer new_map = map_allocator:: allocate ( new_map_size) ;
new_nstart = new_map + ( new_map_size - new_num_nodes) / 2
+ ( add_at_front ? nodes_to_add : 0 ) ;
copy ( start. node, finish. node + 1 , new_nstart) ;
map_allocator:: deallocate ( map, map_size) ;
map = new_map;
map_size = new_map_size;
}
start. set_node ( new_nstart) ;
finish. set_node ( new_nstart + old_num_nodes - 1 ) ;
}
void reserve_map_at_back ( size_type nodes_to_add = 1 ) {
if ( nodes_to_add + 1 > map_size - ( finish. node - map) )
reallocate_map ( nodes_to_add, false ) ;
}
void reserve_map_at_front ( size_type nodes_to_add = 1 ) {
if ( nodes_to_add > start. node - map)
reallocate_map ( nodes_to_add, true ) ;
}
template < class T , class Alloc , size_t BufSize>
void deque< T, Alloc, BufSize> :: push_front_aux ( const value_type& t) {
value_type t_copy = t;
reserve_map_at_front ( ) ;
* ( start. node - 1 ) = allocate_node ( ) ;
__STL_TRY{
start. set_node ( start. node - 1 ) ;
start. cur = start. last - 1 ;
construct ( start. cur, t_copy) ;
}
catch ( . . . ) {
start. set_node ( start. node + 1 ) ;
start. cur = start. first;
deallocate_node ( * ( start. node - 1 ) ) ;
throw ;
}
}
void push_front ( const value_type& t) {
if ( start. cur != start. first) {
construct ( start. cur - 1 , t) ;
-- start. cur;
}
else
push_front_aux ( t) ;
}
template < class T , class Alloc , size_t BufSize>
typename deque< T, Alloc, BufSize> :: iterator
deque< T, Alloc, BufSize> :: insert_aux ( iterator pos, const value_type& x) {
difference_type index = pos - start;
value_type x_copy = x;
if ( index < size ( ) / 2 ) {
push_front ( front ( ) ) ;
iterator front1 = start;
++ front1;
iterator front2 = front1;
++ front2;
pos = start + index;
iterator pos1 = pos;
++ pos1;
copy ( front2, pos1, front1) ;
}
else {
push_back ( back ( ) ) ;
iterator back1 = finish;
-- back1;
iterator back2 = back1;
-- back2;
pos = start + index;
copy_backward ( pos, back2, back1) ;
}
* pos = x_copy;
return pos;
}
iterator insert ( iterator position, const value_type& x) {
if ( position. cur == start. cur) {
push_front ( x) ;
return start;
}
else if ( position. cur == finish. cur) {
push_back ( x) ;
iterator tmp = finish;
-- tmp;
return tmp;
}
else {
return insert_aux ( position, x) ;
}
}
iterator erase ( iterator pos) {
iterator next = pos;
++ next;
difference_type index = pos - start;
if ( index < ( size ( ) >> 1 ) ) {
copy_backward ( start, pos, next) ;
pop_front ( ) ;
}
else {
copy ( next, finish, pos) ;
pop_back ( ) ;
}
return start + index;
}
iterator erase ( iterator first, iterator last) ;
}