Internal realization principle and basic usage of STL vector

Source: Internet
Author: User
Tags exception handling

This paper is based on STL vector source code, but does not consider allocator allocator, iterator iterator, exception handling try/catch and so on, and _ucopy (), _umove (), _ufill () function will not be overly analyzed. I. Definition of vector

Template<class _ty,
    class _ax>
    class vector
        : Public _vector_val<_ty, _ax>
    {   // Varying size array of values public
:
    /********/
protected:
    pointer _myfirst;   Pointer to beginning of array
    pointer _mylast;    Pointer to the sequence
    pointer _myend;//Pointer to end of array
    };

The simple understanding is that vector is represented by the three pointers above, and the basic schematic diagram is as follows:

Two key sizes:
Size: Size=_mylast-_myfirst;
Capacity: Capacity=_myend-_myfirst;
Corresponds to resize (), reserve () two functions respectively.
The size represents the number of elements that are already in the vector, and the capacity represents the number of elements that the vector can store; In order to reduce the cost of two allocations, the vector's actual size may be larger than the customer's needs for future expansion, which is the concept of capacity. That is capacity>=size, when equal, the container is full at this time, if you want to add new elements, the memory allocation, the entire vector of data to move to new memory. The secondary allocation cost is high, in the actual operation, should try to reserve a certain space, avoid two times distribution. ii. structure and deconstruction

1. Construction
Vector constructors are mainly of the following types:

    Vector (): _mybase ()
        {   //construct empty vector
        _buy (0);
        }       
    Explicit vector (Size_type _count): _mybase ()
        {   //construct from _count * _ty () _construct_n (
        _count, _ty ()) ;
        }
    Vector (Size_type _count, const _ty& _val): _mybase ()
        {   //construct from _count * _val
        _construct_n (_ Count, _val);
        }
    Vector (const _myt& _right): _mybase (_right._alval)
        {   //construct by copying _right
        if (_buy (_ Right.size ())
            _mylast = _ucopy (_right.begin (), _right.end (), _myfirst);
        

One of the secrets of the vector's excellent performance is to configure more memory than the elements it holds, and generally reserve enough space to avoid two allocations before using vector, which makes the vector performance best. So the number of elements _count is a much more important parameter than the element value _val, so when constructing a vector, the first parameter must be the number of elements.
It is known from the above constructors that basically all constructors are based on _construct _n ()

    BOOL _buy (Size_type _capacity)
        {   //allocate array with _capacity elements _myfirst =
        0, _mylast = 0, _myend = 0;
        if (_capacity = 0)    //_count is 0 o'clock, return directly
            (false);
        else
            {   //nonempty array, allocate storage
            _myfirst = this->_alval.allocate (_capacity);  Allocate memory and update member variable
            _mylast = _myfirst;
            _myend = _myfirst + _capacity;
            }
        return (TRUE);
        }

    void _construct_n (Size_type _count, const _ty& _val)
        {   //construct container if (_count) containing _val-valued elements _buy
        (_count) )
            _mylast = _ufill (_myfirst, _count, _val);
        

This completes the construction of the vector container.

2, destructor
The vector destructor is simple, destroying all existing elements and freeing all memory

    void _tidy ()
        {   //FREE all storage
        if (_myfirst!= 0)
            {   //something to free, destroy and deallocate I T
            _destroy (_myfirst, _mylast);
            This->_alval.deallocate (_myfirst, _myend-_myfirst);
            }
        _myfirst = 0, _mylast = 0, _myend = 0;
        }
iii. inserting and deleting elements

Vector insertion and deletion elements are implemented through the Push_ back (), Pop_back () two interfaces, and their internal implementations are very simple

    void push_back (const _ty& _val)
        {   //Insert element at end
        if (size () < capacity ())
            _mylast = _ Ufill (_mylast, 1, _val);
        else
            Insert (end (), _val);    With insufficient space, it triggers two allocations of memory
        }

    void Pop_back ()
        {   //erase element at end
        if (!empty ())
            {   / /Erase last element
            _destroy (_mylast-1, _mylast);
            --_mylast
            }
        }
Iv. Other Interfaces

1. Reserve () operation

Previously mentioned the reserve (count) function is primarily reserved for the size of the count space, corresponding to the capacity of the container, the purpose is to ensure (_myend-_myfirst) >=count. It only operates when there is not enough space to redistribute a piece of memory, copy the original elements to the new memory, and destroy the original memory

    void Reserve (Size_type _count)
        {   //determine new minimum length of allocated storage
        if (capacity () < _cou NT)
            {   //Not enough room, reallocate
            pointer _ptr = this->_alval.allocate (_count);
            _umove (Begin (), End (), _ptr);
            Size_type _size = Size ();
            if (_myfirst!= 0)
                {   //Destroy and deallocate old array
                _destroy (_myfirst, _mylast);
                This->_alval.deallocate (_myfirst, _myend-_myfirst);
                }
            _myend = _ptr + _count;
            _mylast = _ptr + _size;
            _myfirst = _ptr;
            }
        

2, resize () operation
The Resize (Count) function is primarily used to change the size of a vector, which in turn changes the value of (_mylast-_myfirst) and inserts the element when size < Count, when size is >count, Erases the element.

    void Resize (Size_type _newsize, _ty _val)
        {   //Determine new length, padding with _val elements as needed
        if ( Size () < _newsize)
            _insert_n (End (), _newsize-size (), _val);
        else if (_newsize < size ())
            Erase (Begin () + _newsize, End ());
        }

3, _insert_n () operation

The resize () operation and the Insert () operation take advantage of the _insert_n () function, which is very important and slightly more complex than the other functions.
Although _insert_n (_where, _count, _val) function is relatively long, but the operation is very simple, mainly can be divided into the following situations:

1, _count = = 0, do not need to insert, direct return

2, Max_size ()-size () < _count, exceeding the maximum capacity of the system setup, will overflow, resulting in Xlen () exception 3, _capacity < size () + _count,vector capacity is not enough to insert the Count element. Two allocations are required to enlarge the capacity of the vector. Under VS, the vector capacity will expand by 50%, i.e. _capacity = _capacity + _capacity/2;
If still insufficient, then _capacity = size () + _count;

    else if (_capacity < size () + _count)
            {   //Not enough room, reallocate
            _capacity = max_size ()-_capacity/ 2 < _capacity
                0: _capacity + _capacity/2;    Try to grow by 50%
            if (_capacity < size () + _count)
                _capacity = size () + _count;
            Pointer _newvec = This->_alval.allocate (_capacity);
            Pointer _ptr = _newvec;
            _ptr = _umove (_myfirst, _vec_iter_base (_where), _newvec);    Copy prefix
            _ptr = _ufill (_ptr, _count, _val);  Add New Stuff
            _umove (_vec_iter_base (_where), _mylast, _ptr);  Copy suffix
            //memory release and variable update
            }

In this case, the data is moved from the original container to the newly allocated memory, from the previous to the back.

4, enough space, and the position of the inserted element is closer to _mylast, that is, the tail of the existing element

In this case, there is no need to allocate memory again, and the data is operated backwards. The first is to move the where~last backwards, to reserve the count size space for the data to be inserted, to start the fill from the _mylast, and then to populate the remaining elements from where

    else if ((Size_type) (_mylast-_vec_iter_base (_where)) < _count)
            {   //new stuff spills off end
            _umove (_vec _iter_base (_where), _mylast,
                _vec_iter_base (_where) + _count);   Copy suffix
            _ufill (_mylast, _count-(_mylast-_vec_iter_base (_where)),
                _val);  Insert new stuff off end
            _mylast + + = _count;
            Std::fill (_vec_iter_base (_where), _mylast-_count,
                _val);  Insert up to old end
            }
5, the space is sufficient, but the insertion position compares the front
            {   //new stuff can all is assigned
            _ty _tmp = _val;    In case _val are in sequence

            pointer _oldend = _mylast;
            _mylast = _umove (_oldend-_count, _oldend,
                _mylast);   Copy suffix
            _stdext _unchecked_move_backward (_vec_iter_base (_where), _oldend-_count, _oldend
                );   Copy hole
            Std::fill (_vec_iter_base (_where), _vec_iter_base (_where) + _count, _tmp
                );  Insert INTO Hole
            }

4, Erase () operation

Iterator Erase (const_iterator _first_arg,
        const_iterator _last_arg)
        {   //erase [_first, _last]
        Iterator _first = _make_iter (_first_arg);
        Iterator _last = _make_iter (_last_arg);

        if (_first!= _last)
            {   //worth doing, copy down-over hole pointer
            = _ptr _stdext (unchecked_copy E (_last), _mylast,
                _vec_iter_base (_first));

            _destroy (_ptr, _mylast);
            _mylast = _ptr;
            }
        return (_first);
        }

The main operation is to copy the valid elements of the latter part forward, to deconstruct the invalid elements in the back space, and to update the _MYLAST variable

5, assign () operation

The Assign () operation eventually calls to the following function, which first erases all elements already in the container and inserts the count Val element from scratch

void _assign_n (Size_type _count, const _ty& _val)
        {   //Assign _count * _val _ty = _tmp _val
        ;    In case _val
        are in sequence erase (begin (), end ());
        Insert (Begin (), _count, _tmp);
        

V. Basic use
After the above analysis of vector internal implementation, it becomes much simpler to understand the corresponding interface.
Vector external interface can be divided into: construction, deconstruction:

ector<elem> c
Vector <Elem> C1 (c2)
vector <Elem> C (n)
vector <Elem> C (n, Elem)
vector <Elem> C (beg,end)
c.~ vector <Elem> ()
Inserts, deletes, assigns a value
C.push_back (elem)
c.pop_back () C.insert (Pos,elem) C.insert (Pos,n,elem) c.insert (Pos,beg
, End)
c.erase (POS)
c.erase (beg,end)
c.clear ()
c.assign (beg,end)
c.assign (N,elem)
Size related
C.capacity ()
c.max_size ()
c.resize (num)
c.reserve ()
c.size ()
Get iterators
C.begin ()
c.end ()
c.rbegin ()
c.rend ()
Get Data
Operator[]
c.at (idx)
C.front ()
c.back ()

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.