Implement STL in shanzhai: vector

Source: Internet
Author: User

First, the definition of vector
Template <typename T>
Class vector
{
};
Let's take a look at some aliases in the vector.
Public:
Typedef T value_type;
Typedef T * pointer;
Typedef T & reference;
Typedef const T & const_reference;
Typedef size_t size_type;
Typedef ptrdiff_t difference_type;
Typedef const T * const_iterator;
Typedef reverse_iterator <const_iterator, value_type, size_type, difference_type> const_reverse_iterator;
Typedef T * iterator;
Typedef reverse_iterator <iterator, value_type, size_type, difference_type> reverse_iterator; as shown in the previous article, vector iterators are implemented by native pointers.

The following are member variables.
Protected:
Typedef vector <T> self;
Typedef allocator <T> Alloc;

Iterator start;
Iterator finish;
Iterator end_of_element; start: point to the starting address of the vector
Finish: the address of the last element.
End_of_element: point to the end position of the applied memory block (finish is always less than or equal to end_of_element)

In STL, from in to end is always expressed in the form of a forward closed and backward open, such as [begin, end ), the advantage of doing so is to make the code write more concise:
Template <typename Iterator, typename T>
Iterator find (Iterator first, Iterator last, const T & value)
{
While (first! = Last & * first! = Value) ++ first;
Return first;
}
Next let's take a look at the most basic constructors and destructor in the vector.
Vector (): start (0), finish (0), end_of_element (0)
{
}

~ Vector ()
{
Destruct (start, end_of_element );
If (start! = 0) Alloc: deallocate (start, end_of_element-start );
} Here, all three member variables are filled with 0.
As mentioned in the previous article, memory allocation and object initialization are separated in STL, and the object structure and memory release are also separated.

Then its begin and end methods are used to obtain the iterator for the last element and the last element.
Inline iterator begin ()
{
Return start;
}

Inline const_iterator begin () const
{
Return start;
}

Inline iterator end ()
{
Return finish;
}

Inline const_iterator end () const
{
Return finish;
}
Front and back are used to obtain the first and last elements respectively.
Inline reference front ()
{
Return * begin ();
}

Inline const_reference front () const
{
Return * begin ();
}

Inline reference back ()
{
Return * (end ()-1 );
}

Inline const_reference back () const
{
Return * (end ()-1 );
}
Empty, size, and capacity are used to determine whether the container is empty, the number of elements in the container, and the container size.
Inline bool empty () const
{
Return begin () = end ();
}

Inline const size_type size () const
{
Return size_type (end ()-begin ());
}

Inline const size_type capacity () const
{
Return size_type (end_of_element-begin ());
}
Because inserting an element in the vector header causes all elements to move behind, it should be designed to be unidirectional and can only be inserted or removed from the end.
Void push_back (const T & x)
{
If (end_of_element! = Finish)
{
Construct (& * finish, x );
++ Finish;
}
Else
{
Insert_aux (end (), x );
}
}

Inline void pop_back ()
{
-- Finish;
Destruct <T> (finish, has_destruct (* finish ));
} Of course, it is not impossible to remove data from the header. You can use the erase method to remove the data from the header. The erase method will be described later.

Let's take a look at the insert_aux method, which is almost used when inserting elements.
Void insert_aux (const iterator position, const T & x)
{
If (finish! = End_of_element)
{
Construct (& * finish, * (finish-1 ));
T x_copy = x;
Copy_backward (position, finish-1, finish );
* Position = x_copy;
++ Finish;
}
Else
{
Const size_type old_size = size ();
Const size_type new_size = old_size = 0? 2: old_size * 2;
Iterator tmp = Alloc: allocate (new_size );
Uninitialized_copy (begin (), position, tmp );
Iterator new_position = tmp + (position-begin ());
Construct (& * new_position, x );
Uninitialized_copy (position, end (), new_position + 1 );
Destruct (begin (), end ());
Alloc: deallocate (begin (), old_size );
End_of_element = tmp + new_size;
Finish = tmp + old_size + 1;
Start = tmp;
}
} When the container still has enough space, first move the element from position to finish to a position, finally, the element to be inserted is written to the original position and the value of the finish pointer is changed.
If the space is insufficient, first apply for memory based on twice the size of the original space, and then copy the elements from the begin to position of the original location to the newly applied memory, insert the element value to be inserted at the specified position of the newly applied memory, and finally copy the remaining part. Analyze the original elements and release the memory.

Why not use reallocate?
Reallocate does not mean to increase or decrease the memory at the original memory location. reallocate first tries to increase or decrease the memory at the original memory location, if it fails, a new memory will be applied again and the original data will be copied. This operation is essentially equivalent to re-applying a memory. Here we should use allocate instead of reallocate.

Then let's take a look at the insert and erase methods.
Inline iterator insert (iterator position, const T & x)
{
Const size_type pos = position-begin ();
If (finish! = End_of_element & position = end ())
{
Construct (& * finish, x );
++ Finish;
}
Else insert_aux (position, x );
Return begin () + pos;
}

Iterator erase (iterator position)
{
Destruct (position, has_destruct (* position ));
If (position + 1! = End ())
{
Copy (position + 1, end (), position );
}
-- Finish;
Return position;
} If you want to insert an element at the end and the remaining space of the container is sufficient, insert the element directly to the finish position and move the finish pointer one after. If the container space is insufficient or is not inserted in the last position, call insert_aux to re-allocate memory or insert.
When deleting an element, the original element is first parsed. If the deleted element is not the last element, all the elements following the deletion are copied and the finish pointer is moved to a new position. Www.2cto.com

Finally, let's take a look at the overloaded operators.
Self & operator = (const self & x)
{
If (& x = this) return * this;
Size_type const other_size = x. size ();
If (other_size> capacity ())
{
Destruct (start, finish );
Alloc: deallocate (start, capacity ());
Start = Alloc: allocate (other_size );
Finish = uninitialized_copy (x. begin (), x. end (), start );
End_of_element = start + other_size;
}
Else
{
Finish = uninitialized_copy (x. begin (), x. end (), start );
}
Return * this;
}

Inline reference operator [] (size_type n)
{
Return * (begin () + n );
}

Inline value_type at (size_type n)
{
Return * (begin () + n );
} Because vector uses native pointers internally, the usage of these operators is no different from that of native pointers. It is worth noting that the memory will be re-allocated and copied during the value assignment operation.

Author: lwch
 

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.