STL源码之vector

STL源码之vector

 

1. SGI的vector

SGI stl vector继承子一个基类:

template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class vector : protected _Vector_base<_Tp, _Alloc>

在基类中定义了基本的一些操作,并且封装了了vector所需要的基本的三个指针:

struct _Vector_impl
      : public _Tp_alloc_type
      {
    pointer _M_start;
    pointer _M_finish;
    pointer _M_end_of_storage;

     …

}

public:
      _Vector_impl _M_impl;

以_M_impl作为数据成员。

现在我们只在一个类中表达出相同含义。

2. vector基本含义

#include <memory>
 
 template <typename T, typename Alloc = std::allocator<T> >
 class vector
 {
 public:
    //必须的嵌套类型,必须包含iterator_traits中五个类型
    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 value_type*                            iterator;
    typedef const value_type*                       const_iterator;
    typedef std::reverse_iterator<const_iterator>  const_reverse_iterator;
    typedef std::reverse_iterator<iterator>        reverse_iterator;
    typedef size_t                                    size_type;
    typedef ptrdiff_t                                difference_type;
    typedef Alloc                                  allocator_type;    
protect:
    iterator start;                //目前使用空间的头:beginn()
    iterator finish;            //目前使用空间尾:end()
    iterator end_of_storage;    //目前可用空间的尾:capacity()
    
    //分配内存时,实际分配的类型。
    //对于vector,值类型是T,实际分配的类型也是T,other 就是 Alloc<T>
    //但是对于其它一些类型就不一定了。
    //比如:list的值类型为T,实际分配的类型是其list_node<T>类型。
    typedef typename template rebind<T>::other T_alloc_type;
    
     T_alloc_type& 
     get_T_allocator() noexcept()
      { return *start; }

      const T_alloc_type&
      get_T_allocator() const noexcept()
      { return *start; }

      allocator_type
      get_allocator() const noexcept()
      { return allocator_type(get_T_allocator()); }
      
      pointer
      _M_allocate(size_t __n)
      {
    typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;
    return __n != 0 ? _Tr::allocate(_M_impl, __n) : 0;
      }

      void
      _M_deallocate(pointer __p, size_t __n)
      {
    typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;
    if (__p)
      _Tr::deallocate(_M_impl, __p, __n);
      }
    
    //主要的构造函数和复制控制函数
     vector():start(0), finish(0), end_of_storage(0) {}
           
     vector(size_type n, const T& value)
    { 
        fill_initialize(n, value); 
    }
    
     explicit vector(size_type n)
    { 
        default_initialize(n); 
    }
    
    vector(const vector& x)
    { 
        create_storage(n);
        this->finish = std::uninitialized_copy(x.begin(), x.end(), this->start);
    }
     b
private:
    create_storage(size_t n)
    {
        this->start = Alloc.allocate(n);
        this->finish = this->start;
        this->end_of_storage = this->start + n;
        
    }
    void fill_initialize(size_type n, const value_type& value)
    {
        create_storage(n);
        
        std::uninitialized_fill_n(start, n, value);
        this->finish = this->storage;
    }
    
    #if __cplusplus >= 201103L
      // Called by the vector(n) constructor.
     void default_initialize(size_type n)
    {
        create_storage(n);
        
        std::uninitialized_default_n(start, n);
        this->finish = end_of_storage;
    }
#endif
}

3.构造函数基本的要点
(1) vector<T> vec; //默认构造函数使start = finish = end_of_storage = 0;
(2) vector<T> vec(10); //构造10个T()的元素,finish = end_of_storage = start + 10;
capacity()与size()相同。
(3) vector<T> vec(10, value); //构造10个值为value的元素,finish = end_of_storage = start + 10;
capacity()与size()相同。
(4) vector<T> vec(vec2); //vec的容量与大小相同

4. 插入的特点
(1)insert(position, value);
if (finish != end_of_storage) { //剩余空间足够:直接构造元素,调整finish。
//在finish构造元素,值为最后一个元素值
construct(finish, *(finish -1 ));
++finish;
T x_copy = x;
//把postion到最后一个元素之前的元素向后插入到最后位置
copy_backward(position, finsish - 2, finish - 1);
*posion = x_copy;
} else { //没有剩余空间
//size()扩大两倍(VS增加大小的一半).原本为0,则size() = 1; capacity = 1;
//将vector中start..position中元素拷贝到新空间
//在position构造元素
//在把之后的元素复制到新空间中

//释放原本空间
destroy(begin(), end());
deallocate();


(2) insert(position, n, value);
if (n != 0) {
if (备用空间 >= n) {
if (positionz之后元素 > n) {
先把尾部前的n个元素移到后面
把position后剩余元素向后复制到尾部前
填充n个新值
} else {
现在尾部fill元素少的元素
调整finish
把元素复制到新尾部
fill剩余的元素
}
} else {
//size()扩大两倍或者原本长度 + n
//将vector中start..position中元素拷贝到新空间
//在position构造n个元素
//在把之后的元素复制到新空间中

//释放原本空间
destroy(begin(), end());
deallocate();
}
}

总结:一旦剩余空间不够,就需要扩充空间,复制元素,释放原空间。所以可以事先确定好大小或者容量。

5. 关于大小和容量
(1) resize(n)时,n >= size()使用默认构造初始化多的元素。n < size()截断元素。
(2) vector<T> vec;
vec.reserve(n); //start = finish = 0; end_of_storage = start + n;
容器中没有元素,此时可以vec[i],但是finish不会改变,即size()还是==0;
此时要想正确的改变size(),必须使用push_back()或者insert()。

整体行为就是,若n > 现有容量,扩大容量。把旧元素复制到新的空间,然后释放原空间。否则,忽略。
(3) erase(position); erase(first, last);时:将后面元素复制到erase的位置(就是直接覆盖),
只是改变了size()。元素capacity()没有改变。
clear()是同样的情景,clear() = earse(begin(), end());
(4) 一般情况下容量从不改变,改变的只是size()。
shrink_to_fit()可以压缩容量的函数。
~vector(); //可以释放空间,size() = capacity() = 0;




原文地址:https://www.cnblogs.com/hancm/p/3840425.html