stl source analysis - list of sequences container

  Longer data structures learned in the past, the definition of the structure and behavior of the list had to know, so read the source code learning stl container defined list is not difficult.

  vector list are two commonly used with containers with different vector, not a continuous linear space list, a doubly linked list. Every insert or delete an element, the element configuration or release a space, therefore, list for the use of space with absolute precision, without causing waste. And the element for inserting or deleting any location of which the operating time is always constant time. (The disadvantage is not random access)

 

list node

  list and list itself are designed separately node list, the list node structure

template <class T>  
  struct __list_node {  
    typedef void* void_pointer;  
    void_pointer next;  
    void_pointer prev;  
    T data;  
  };  

  It can be seen node list is a doubly linked list, next pointing to the next node, prev previous node point

 

list iterator

  Learned data structure will know, a characteristic list of its allocated space is not necessarily fixed in a contiguous storage space, the list not like vector as ordinary pointers as iterators, since its node can not guarantee that a continuous presence in the storage space. list iterator must be able to point to its list node, and the ability to correct increasing, decreasing, value, member access and other operations.

  Because STL list is a doubly linked list, iterators must have moved forward, backward capability, so the list is provided Bidirectional Iterators (bidirectional iterators).

  In the vector, its insertion is likely to make full and overflow, this vector would need to reconfigure the space, so that the original iteration will all fail. The list is made to insert and engaging operation will not cause the original list iterator failure, even its deletion, and only "point to the deleted elements" iterator fails, other iterators are not affected.

 

 

template<class T,class Ref,class Ptr>
  struct _list_iterator{
      typedef _list_iterator<T,T&,T*> iterator;
      typedef _list_iterator<T,T&,T*> iterator;
      typedef bidirectional_iterator_tag iterator_category;
      typedef T value_type;
      typedef Ptr pointer;
      typedef Ref reference;
      typedef _list_node<T>* link_type;
      typedef size_t size_type;
      typedef ptrdiff_t difference_type;
      
      link_type node;
      
      _list_iterator(link_type x):node(x){}
      _list_iterator(){}
      _list_iterator(const iterator& x):node(x.node){}
      
      bool operator==(const self& x) const {return node==x.node;}
      bool operator!=(const self& x) const {return node!=x.node;}

      reference operator*() const {return (*node).data;}

      reference operator->() const {return &(operator*());}
      

      self& operator++(){
          node=(link_type)((*node).next);
          return *this;
      }
      self operator++(int){
          self tmp=*this;
          ++*this;
          return tmp;
      }

      self& operator--(){
          node=(link_type)((*node).prev);
          return *this;
      }
      self operator--(int){
          self tmp=*this;
          --*this;
          return tmp;
      }
  }

 

list data structure

  SGI list is not only a doubly linked list, but a circular doubly linked list.

Template < class T, class of Alloc = alloc> // defaults to alloc configurator 
  class List {  
   protected :  
      typedef __list_node<T> list_node ;  
  public  :  
      typedef list_node* link_type ;  
  protected :  
      the Node LINK_TYPE; // just a pointer, it can represent the entire ring doubly linked list   
      ...
  };

If you let the pointer points to node deliberately placed in the end of a blank node, the node will be able to meet the requirements for stl open interval before and after closing, becoming the last iterator. The following functions will be able to easily complete this

iterator begin() { return (link_type)((*node).next); }
iterator end() { return node; }

bool empty() const { return node->next == node; }

size_type size() const
{
    size_type result = 0;
    distance (begin (), end (), result); distance function // SGI role which is to traverse the list, very affecting performance
    return result;
}

reference front() { return *begin(); }
reference back() { return *(--end()); }

 

 

 

list of construction and Memory Management

  There are many ways list of construction, listed here in the default constructor

/ Default allocator is alloc
template <class T, class Alloc = alloc>
class list
{
...
public:
    list() { empty_initialize(); }
protected : 
     // exclusive space configuration, a configuration of a node unit size 
    typedef simple_alloc <List_node, of Alloc> list_node_allocator;

    // create an empty list 
    void empty_initialize ()
    {
        node = get_node();
        node->next = node;
        node->prev = node;
    }

    // configure a node, not configured 
    LINK_TYPE get_node () { return list_node_allocator :: the allocate ();}

    // release a node, without destructor 
    void put_node (LINK_TYPE P) {list_node_allocator :: DEALLOCATE (P);}

    // arranged and configured in a node 
    LINK_TYPE create_node ( const T & X)
    {
        link_type p = get_node();
        construct(&p->data, x);
        return p;
    }

    // destructor and release node 
    void destroy_node (LINK_TYPE P)
    {
        destroy(&p->data);
        put_node(p);
    }
...
}

  insetr () function is a heavy load, it also has many forms, the simplest of the following, a first node configured and arranged, then make the appropriate pointer operation new node is inserted at the end (push_back () and inserting a new element when push_front invokes insert ())

 

iterator insert(iterator position, const T& x)
{
    tmp LINK_TYPE = create_node (X);    // generates a node
     // adjust bidirectional pointers so tmp inserted 
    tmp-> Next = position.node;
    tmp->prev = position.node->prev;
    (link_type(position.node->prev))->next = tmp;
    position.node->prev = tmp;
    return tmp;
}

 

list of operating elements

  Many elements of the operation list, whether it is a simple insertion or deletion Clear migration, most of them difficult, some common operations listed below only are interested can read "stl-source analysis" about the contents of Chapter IV of the list, or download the source to study

void push_front(const T&x){  
  insert(begin(),x);  
  }

 iterator erase(iterator position){  
      link_type next_node=link_type(position.node->next);  
      link_type prev_node=link_type(position.node->prev_nodext);  
      prev_node->next=next_node;  
      next_node->prev=prev_node;  
      destroy_node(position.node);  
      return iterator(next_node);  
  } 

void pop_front(){  
      erase(begin());  
  } 

void pop_back(){  
      iterator i=end();  
      erase(--i);  
  } 


// migrating a continuous range of elements before a specific location. Technically very simple, direct pointer nodes move it. 
void Transfer (Iterator position, Iterator First, Last Iterator) {  
       IF (position! = Last) {  
        (*(link_type((*last.node).prev))).next = position.node; 
        (*(link_type((*first.node).prev))).next = last.node;      
        (*(link_type((*position.node).prev))).next = first.node;  
        link_type tmp = link_type((*position.node).prev);       
        (*position.node).prev = (*last.node).prev;               
        (*last.node).prev = (*first.node).prev;                  
        (*first.node).prev = tmp;                               
      }  
    }  

 

Guess you like

Origin www.cnblogs.com/LEEYATWAH/p/11707589.html