SGI STL source vector analysis

Foreword

vector is the most common C ++ container, its dynamic expansion feature is not available in ordinary array, greatly increasing the flexibility of programming. Although a basic understanding of the basic principles of energy, but can not understand the deep-seated until the reading of a vector source, be able to say more confident of their true understanding of the basic principles of the vector, is to be said of that sentence Hou Jie: Source in front, the no password. I will be divided into two articles were analyzed and generalized vector specialization vector bool type for (that is, bit_vector, bit vector). This paper will analyze the generalization of the vector source.

vector overview

A vector is a dynamic array of continuous expansion. Normal arrays are static space, once configured can not be changed, while the vector is a dynamic space, the internal mechanism will automatically expand the space to accommodate more elements. Dynamic expansion of its specific process is: when the container is no spare space, will open up a new space is twice the size of the old space, copy the data from the old space to the new space and the release of the original space. Consequently, vector of great help for the rational use of memory and application flexibility, I did no longer have to consider the problem of insufficient capacity of the array.

vector source code analysis

This paper analyzes the source code vector is Hou Jie teacher "STL source code analysis" version of SGI-STL-v2.91 is used. Version vector generalization embodied in stl_vector.h file, part of the source code as follows:

// the alloc space is SGI STL configurator 
Template < class T, class of Alloc the alloc =>
 class Vector {
 public :
    typedef T value_type;
    typedef value_type* pointer;
    typedef const value_type* const_pointer;
    typedef value_type* iterator;
    typedef const value_type* const_iterator;
    typedef value_type& reference;
    typedef const value_type& const_reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

__STL_CLASS_PARTIAL_SPECIALIZATION #ifdef   // here, reverse iterator can ignore the first 
  typedef reverse_iterator <const_iterator> a const_reverse_iterator;
  typedef reverse_iterator<iterator> reverse_iterator;
#endif

protected :
     // simple_alloc is SGI STL spatial configuration, a source is the use of this interface all containers 
    typedef simple_alloc <the value_type, of Alloc> data_allocator;

    Start Iterator;            // represents the head space currently used 
    Iterator Finish;           // represents the space currently used tail 
    Iterator end_of_storage;   // represents the end of the current free space

    void insert_aux(iterator position, const T& x);
    void deallocate() {
        if(start)
            data_allocator::deallocate(start, end_of_storage - start);
    }
    void fill_initialize(size_type n, const T& value) {
        start = allocate_and_fill(n, value);
        finish = start + n;
        end_of_storage = finish;
    }

public:
    iterator begin() { return start; }
    const_iterator begin() const { return start; }
    iterator end() { return finish; }
    const_iterator end() const { return finish; }
    reverse_iterator rbegin() { return reverse_iterator(end()); }
    const_reverse_iterator rbegin() const {
        return const_reverse_iterator(end());
    }
    reverse_iterator rend() { return reverse_iterator(begin()); }
    const_reverse_iterator rend() const {
        return const_reverse_iterator(begin());
    }
    size_type size() const {
        return size_type(end() - begin());
    }
    size_type max_size() const {
        return size_type(-1) / sizeof(T);
    }
    size_type capacity() const {
        return size_type(end_of_storage - begin());
    }
    bool empty() const { return begin() == end(); }

    reference operator[](size_type n) {
        return *(begin() + n);
    }
    const_reference operator[](size_type n) const {
        return *(begin() + n);
    }
    
    vector() : start(0), finish(0), end_of_storage(0) {}
    vector(size_type n, const T& value) {
        fill_initialize(n, value);
    }
    vector(int n, const T& value) {
        fill_initialize(n, value);
    }
    vector(long n, const T& value) {
        fill_initialize(n, value);
    }
    explicit vector(size_type n) {
        fill_initialize(n, T());
    }
    vector(const vector<T, Alloc>& x) {
        start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
        finish = start + (x.end() - x.begin());
        end_of_storage = finish;
    }
    template <class InputIterator>
    vector(InputIterator first, InputIterator last) :
        start(0), finish(0), end_of_storage(0)
    {
        range_initialize(first, last, iterator_category(first));
    }

    ~vector() {
        the destroy (Start, Finish);   // global variable 
        deallocate ();
    }

    vector<T, Alloc>& operator=(const vector<T, Alloc>& x);

    void reverve(size_type n) {
        if (capacity() < n) {
            const size_type old_size = size();
            iterator tmp = allocate_and_copy(n, start, finish);
            destroy(start, finish);
            deallocate();
            start = tmp;
            finish = start + old_size;
            end_of_storage = start + n;
        }
    }

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

    void push_back ( const T & X) {
         IF (Finish = end_of_storage!) {   // there is spare space 
            Construct (Finish, X);   // global function 
            ++ Finish;
        } The else   // no spare space 
            insert_aux (End (), X);   // member function, subsequent analyzes 
    }

    void swap(vector<T, Alloc>& x) {
        __STD::swap(start, x.start);
        __STD::swap(finish, x.finish);
        __STD::swap(end_of_storage, x.end_of_storage);
    }
    
    // and push_back not very different, but not the same as the insertion position, complicated 
    Iterator INSERT (Iterator position, const T & X) {  
        size_type n = position - begin();
        if (finish != end_of_storage && position == end()) {
            construct(finish, x);
        } else 
            insert_aux(position, x);

        return begin() + n;
    }
    
    iterator insert(iterator position) {
        insert(position, T());
    }

    #ifdef __STL_MEMBER_TEMPLATES
    template <class InputIterator>
    void insert(iterator position, InputIterator first, InputIterator last) 
    {
        range_insert(position, first, last, iterator_category(first));
    }
    #endif

    void insert(iterator pos, size_type n, const T& x);

    void insert(iterator pos, int n, const T& x) {
        insert(pos, (size_type) n, x);
    }
    
    void insert(iterator pos, long n, const T& x) {
        insert(pos, (size_type) n, x);
    }

    void pop_back() {
        --finish;
        the destroy (Finish);     // finish-> ~ T here is call the destructor referents pointers finish, can not release memory 
    }
  
    iterator erase(iterator position) {
        // If you remove is not the last element 
        IF (position + 1 ! = End ())
            Copy (position + . 1 , Finish, position);   // global function

        --finish;
        destroy(finish);
        return position;
    }

    // remove the half-closed interval [First, last) among all the elements, last point of the element is not removed 
    iterator erase (iterator first, iterator last ) {
        I Iterator = Copy (Last, Finish, First);  
         // if the destructor is trivial in the interval of elements, do nothing
         // if the destructor in the interval element is non-trivial, the sequence calling its destructor 
        destroy (i, finish);    
        finish = finish - (last - first);    //重新调整finish
        return first;
    }
    
    void resize(size_type new_size, const T& x) {
        if (new_size < size()) 
            erase(begin() + new_size, end());
        else
            insert(end(), new_size - size(), x);
    }
    
    void resize(size_type new_size) { resize(new_size, T()); }

    void clear() { erase(begin(), end()); }

protected :
     // configuration space and fills the contents 
    Iterator allocate_and_fill (n-size_type, const T & X) {
        iterator result = data_allocator::allocate(n);
        __STL_TRY 
        {
            uninitialized_fill_n(result, n, x);
            return result;
        }
        __STL_UNWIND(data_allocator::deallocate(result, n));
    }
      template <class ForwardIterator>
      iterator allocate_and_copy(size_type n,
                                 ForwardIterator first, ForwardIterator last) {
          iterator result = data_allocator::allocate(n);
          __STL_TRY {
              uninitialized_copy(first, last, result);
              return result;
          }
          __STL_UNWIND(data_allocator::deallocate(result, n));
      }
/ * ******************************************************** follow-up as well as *********************** ******** * /

vector iterator

maintenance is a continuous vector space so no matter what type of its elements do not, ordinary pointers can meet all the necessary conditions as a vector iterator, because vector iterator desired operating behavior, such as operator *, operator ++, operator-- , operator +, operator-, operator + =, operator- =, includes a general pointer, can be seen from the above code, the iterator is an ordinary vector with pointer. But in addition to bool type, although ordinary pointer as applicable, in order to improve space utilization, the source code has been designed specifically iterators for specialized version of the design, the next article will explore further.

insert_aux analysis
insert_aux vector is the key dynamic expansion, the specific source code as follows:
Template < class T, class of Alloc>
 void Vector <T, of Alloc> :: insert_aux (Iterator position, const T & X) {
     IF (Finish! = end_of_storage) {   // there is a spare space
         // in the spare space at the beginning of a construction element, and to the last element vector whose initial value is 
        Construct (Finish, * (Finish - . 1 ));
         ++ Finish;
        X_copy T = X;
         // global function, forward from the back finish-1 replication [position, finish-2] value 
        copy_backward (position, Finish - 2 , Finish - . 1 ); 
         * = position x_copy;
    } The else {
         const size_type old_size = size ();
         const ! Size_type len = old_size = 0 ? 2 * old_size: 1 ;   // current space twice the size 
        Iterator NEW_START = data_allocator :: the allocate (len);
        iterator new_finish = new_start;
        __STL_TRY
        {
            //复制[start,position)复制到new_start,new_finish为new_start+(position-start)
            new_finish = uninitialized_copy(start, position, new_start);
            construct(new_finish, x); 
            new_finish ++; // adjust the water level
             // replication [position, finish) copied to new_finish 
            new_finish = uninitialized_copy (position, Finish, new_finish);
        }
        catch(...) {
            destroy(new_start, new_finish); 
            data_allocator::deallocate(new_start, len);
            throw;
        }
        the destroy (the begin (), End ()); // call the destructor old space element 
        DEALLOCATE (); // release the old space 
        Start = NEW_START;
        finish = new_finish;
        end_of_storage = new_start + len;
    }
}

 As can be seen from the above source, the so-called dynamic expansion, the new space not continue after the original space, because the space can not be guaranteed after the original space still configurable. But at twice its original size in addition to configure a larger space, and then copy over the original content (note that this technique, in two steps, first copy [start, position), in the new space to be vacated position position, and then copy [position, finish) to the new space) before construct a new element in the position position, and the release of the original space. Therefore, any action on the vector of note, when caused by space reconfiguration, all pointing to the original vector of iterators they all fail.

 

Guess you like

Origin www.cnblogs.com/evenleee/p/11669423.html