STL源码解析—vector

来源:互联网 发布:软件销售笔试题库 编辑:程序博客网 时间:2024/05/17 22:32

vector的数据安排和操作方式类似于C++内置数组类型array,唯一的区别就是在于空间的灵活运用。内置数组array是静态空间,一旦分配了内存空间就不能改变,而vector容器可以根据用户数据的变化而不断调整内存空间的大小。

vector容器有已使用空间和可用空间,已使用空间是指vector容器的大小,可用空间是指vector容器可容纳的最大数据空间capacityvector容器是占用一段连续线性空间,所以vector容器的迭代器就等价于原生态的指针vector的实现依赖于内存的配置和内存的初始化,以及迭代器。其中内存的配置是最重要的,因为每当配置内存空间时,可能会发生数据移动,回收旧的内存空间,如果不断地重复这些操作会降低操作效率,所有vector容器在分配内存时,并不是用户数据占多少就分配多少,它会分配一些内存空间留着备用,即是用户可用空间。


       vector容器采用的是线性连续空间的数据结构,使用两个迭代器来管理这片连续内存空间,这两个迭代器分别是指向目前使用空间的头start和指向目前使用空间的尾finish,两个迭代器的范围[start,finish)表示容器的大小size()。由于为了提高容器的访问效率,为用户分配内存空间时,会分配多余的备用空间,即容器的容量,以迭代器end_of_storage作为可用空间的尾,则容器的容量capacity()[start,end_of_storage)范围的线性连续空间。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //Alloc是SGI STL的空间配置器,默认是第二级配置器  
  2. template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >  
  3. class vector : protected _Vector_base<_Tp, _Alloc>   
  4. {  
  5.        ...  
  6. protected:  
  7.   _Tp* _M_start;//表示目前使用空间的头  
  8.   _Tp* _M_finish;//表示目前使用空间的尾  
  9.   _Tp* _M_end_of_storage;//表示目前可用空间的尾    
  10.     ...  
  11. };  
    下面给出vector的数据结构图:



   vector容器维护的空间的线性连续的,所以普通指针也可以作为迭代器,满足vector的访问操作;如:operator*operator->operator++operator--operator+operator-operator+=operator-=等操作;同时vector容器支持随机访问,所以,vector提供的是随机访问迭代器。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //Alloc是SGI STL的空间配置器,默认是第二级配置器  
  2. template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >  
  3. class vector : protected _Vector_base<_Tp, _Alloc>   
  4. {  
  5.     
  6. public://vector的内嵌型别定义,是iterator_traits<I>服务的类型  
  7.   typedef _Tp value_type;  
  8.   typedef value_type* pointer;  
  9.   typedef const value_type* const_pointer;  
  10.   typedef value_type* iterator;//vector容器的迭代器是普通指针  
  11.   typedef const value_type* const_iterator;  
  12.   ...  
  13.   
  14.   public://以下定义vector迭代器  
  15.   iterator begin() { return _M_start; }//指向已使用空间头的迭代器  
  16.   const_iterator begin() const { return _M_start; }  
  17.   iterator end() { return _M_finish; }//指向已使用空间尾的迭代器  
  18.   const_iterator end() const { return _M_finish; }  
  19.   
  20.   reverse_iterator rbegin()  
  21.     { return reverse_iterator(end()); }  
  22.   const_reverse_iterator rbegin() const  
  23.     { return const_reverse_iterator(end()); }  
  24.   reverse_iterator rend()  
  25.     { return reverse_iterator(begin()); }  
  26.   const_reverse_iterator rend() const  
  27.     { return const_reverse_iterator(begin()); }  
  28.     ...  
  29. };  

这里把vector容器的构造函数列出来讲解

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1.  /*以下是vector容器的构造函数******************************************* 
  2. /********************************************************************** 
  3. *** //默认构造函数***************************************************** 
  4. *   explicit vector( const Allocator& alloc = Allocator() );          * 
  5. *** //具有初始值和容器大小的构造函数*********************************** 
  6. *   explicit vector( size_type count,                                 * 
  7. *                 const T& value = T(),                               * 
  8. *                 const Allocator& alloc = Allocator());              * 
  9. *         vector( size_type count,                                    * 
  10. *                 const T& value,                                     * 
  11. *                 const Allocator& alloc = Allocator());              * 
  12. *** //只有容器大小的构造函数******************************************* 
  13. *   explicit vector( size_type count );                               * 
  14. *** //用两个迭代器区间表示容器大小的构造函数*************************** 
  15. *   template< class InputIt >                                         * 
  16. *   vector( InputIt first, InputIt last,                              * 
  17. *        const Allocator& alloc = Allocator() );                      *   
  18. *** //拷贝构造函数***************************************************** 
  19. *   vector( const vector& other );                                    * 
  20. *   vector( const vector& other, const Allocator& alloc );            *  
  21. *** //移动构造函数***************************************************** 
  22. *   vector( vector&& other );                                         * 
  23. *   vector( vector&& other, const Allocator& alloc );                 * 
  24. *** //用初始列表的值构造容器,列表内的元素值可以不同******************* 
  25. *   vector( std::initializer_list<T> init,                            * 
  26. *        const Allocator& alloc = Allocator() );                      * 
  27. ***********************************************************************/   
  28.   explicit vector(const allocator_type& __a = allocator_type())  
  29.     : _Base(__a) {}//默认构造函数  
  30.   
  31.   vector(size_type __n, const _Tp& __value,  
  32.          const allocator_type& __a = allocator_type())   
  33.     : _Base(__n, __a)//构造函数,里面包含n个初始值为value的元素  
  34.     //全局函数,填充值函数,即从地址M_start开始连续填充n个初始值为value的元素  
  35.     { _M_finish = uninitialized_fill_n(_M_start, __n, __value); }  
  36.   
  37.   explicit vector(size_type __n)//该构造函数不接受初始值,只接受容易包含元素的个数n  
  38.     : _Base(__n, allocator_type())  
  39.     { _M_finish = uninitialized_fill_n(_M_start, __n, _Tp()); }  
  40.   
  41.   vector(const vector<_Tp, _Alloc>& __x)   
  42.     : _Base(__x.size(), __x.get_allocator())//拷贝构造函数  
  43.     { _M_finish = uninitialized_copy(__x.begin(), __x.end(), _M_start); }  
  44.   
  45. #ifdef __STL_MEMBER_TEMPLATES  
  46.   // Check whether it's an integral type.  If so, it's not an iterator.  
  47.   /*这个是某个区间的构造函数,首先判断输入是否为整数_Integral() 
  48.   *采用__type_traits技术 
  49.   */  
  50.   template <class _InputIterator>  
  51.   vector(_InputIterator __first, _InputIterator __last,  
  52.          const allocator_type& __a = allocator_type()) : _Base(__a) {  
  53.     typedef typename _Is_integer<_InputIterator>::_Integral _Integral;  
  54.     _M_initialize_aux(__first, __last, _Integral());  
  55.   }  
  56.   
  57.   template <class _Integer>  
  58.   //若输入为整数,则调用该函数  
  59.   void _M_initialize_aux(_Integer __n, _Integer __value, __true_type) {  
  60.     _M_start = _M_allocate(__n);  
  61.     _M_end_of_storage = _M_start + __n;   
  62.     _M_finish = uninitialized_fill_n(_M_start, __n, __value);  
  63.   }  
  64.   
  65.   template <class _InputIterator>  
  66.   //若输入不是整数,则采用Traits技术继续判断迭代器的类型  
  67.   void _M_initialize_aux(_InputIterator __first, _InputIterator __last,  
  68.                          __false_type) {  
  69.     _M_range_initialize(__first, __last, __ITERATOR_CATEGORY(__first));  
  70.   }  
  71.   
  72. #else  
  73.   vector(const _Tp* __first, const _Tp* __last,  
  74.          const allocator_type& __a = allocator_type())  
  75.     : _Base(__last - __first, __a)   
  76.     { _M_finish = uninitialized_copy(__first, __last, _M_start); }  
  77. #endif /* __STL_MEMBER_TEMPLATES */  
  78.   
  79.   ~vector() { destroy(_M_start, _M_finish); }//析构函数  

   vector容器的成员函数使我们访问容器时经常会用到,为了加深对其了解,这里单独对成员函数源码进行了详细的注解。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1.     /*以下是容器的一些成员函数*/  
  2.   size_type size() const//vector容器大小(已使用空间大小),即容器内存储元素的个数  
  3.     { return size_type(end() - begin()); }  
  4.   size_type max_size() const//返回可容纳最大元素数  
  5.     { return size_type(-1) / sizeof(_Tp); }  
  6.   size_type capacity() const//vector容器可用空间的大小  
  7.     { return size_type(_M_end_of_storage - begin()); }  
  8.   bool empty() const//判断容器是否为空  
  9.     { return begin() == end(); }  
  10.   
  11.   reference operator[](size_type __n) { return *(begin() + __n); }//返回指定位置的元素  
  12.   const_reference operator[](size_type __n) const { return *(begin() + __n); }  
  13.   
  14. #ifdef __STL_THROW_RANGE_ERRORS  
  15.   //若用户要求的空间大于可用空间,抛出错去信息,即越界检查  
  16.   void _M_range_check(size_type __n) const {  
  17.     if (__n >= this->size())  
  18.       __stl_throw_range_error("vector");  
  19.   }  
  20.   
  21.   reference at(size_type __n)//访问指定元素,并且进行越界检查  
  22.     { _M_range_check(__n); return (*this)[__n]; }//访问前,先进行越界检查  
  23.   const_reference at(size_type __n) const  
  24.     { _M_range_check(__n); return (*this)[__n]; }  
  25. #endif /* __STL_THROW_RANGE_ERRORS */  
  26.   
  27.     void reserve(size_type __n) {//改变可用空间内存大小  
  28.     if (capacity() < __n) {  
  29.       const size_type __old_size = size();  
  30.       //重新分配大小为n的内存空间,并把原来数据复制到新分配空间  
  31.       iterator __tmp = _M_allocate_and_copy(__n, _M_start, _M_finish);  
  32.       destroy(_M_start, _M_finish);//释放容器元素对象  
  33.       _M_deallocate(_M_start, _M_end_of_storage - _M_start);//回收原来的内存空间  
  34.       //调整迭代器所指的地址,因为原来迭代器所指的地址已经失效  
  35.       _M_start = __tmp;  
  36.       _M_finish = __tmp + __old_size;  
  37.       _M_end_of_storage = _M_start + __n;  
  38.     }  
  39.   }  
  40.   
  41.   reference front() { return *begin(); }//返回第一个元素  
  42.   const_reference front() const { return *begin(); }  
  43.   reference back() { return *(end() - 1); }//返回容器最后一个元素  
  44.   const_reference back() const { return *(end() - 1); }  
  45.   
  46.   void push_back(const _Tp& __x) {//在最尾端插入元素  
  47.     if (_M_finish != _M_end_of_storage) {//若有可用的内存空间  
  48.       construct(_M_finish, __x);//构造对象  
  49.       ++_M_finish;  
  50.     }  
  51.     else//若没有可用的内存空间,调用以下函数,把x插入到指定位置  
  52.       _M_insert_aux(end(), __x);  
  53.   }  
  54.   void push_back() {  
  55.     if (_M_finish != _M_end_of_storage) {  
  56.       construct(_M_finish);  
  57.       ++_M_finish;  
  58.     }  
  59.     else  
  60.       _M_insert_aux(end());  
  61.   }  
  62.   void swap(vector<_Tp, _Alloc>& __x) {  
  63.       /*交换容器的内容 
  64.       *这里使用的方法是交换迭代器所指的地址 
  65.       */  
  66.     __STD::swap(_M_start, __x._M_start);  
  67.     __STD::swap(_M_finish, __x._M_finish);  
  68.     __STD::swap(_M_end_of_storage, __x._M_end_of_storage);  
  69.   }  
  70.   
  71.   iterator insert(iterator __position, const _Tp& __x) {//把x值插入到指定的位置  
  72.     size_type __n = __position - begin();  
  73.     if (_M_finish != _M_end_of_storage && __position == end()) {  
  74.       construct(_M_finish, __x);  
  75.       ++_M_finish;  
  76.     }  
  77.     else  
  78.       _M_insert_aux(__position, __x);  
  79.     return begin() + __n;  
  80.   }  
  81.   iterator insert(iterator __position) {  
  82.     size_type __n = __position - begin();  
  83.     if (_M_finish != _M_end_of_storage && __position == end()) {  
  84.       construct(_M_finish);  
  85.       ++_M_finish;  
  86.     }  
  87.     else  
  88.       _M_insert_aux(__position);  
  89.     return begin() + __n;  
  90.   }  
  91.   
  92.   void insert (iterator __pos, size_type __n, const _Tp& __x)  
  93.     { //在pos位置连续插入n个初始值为x的元素  
  94.         _M_fill_insert(__pos, __n, __x); }  
  95.   
  96.   void _M_fill_insert (iterator __pos, size_type __n, const _Tp& __x);  
  97.   
  98.   void pop_back() {//取出最尾端元素  
  99.     --_M_finish;  
  100.     destroy(_M_finish);//析构对象  
  101.   }  
  102.   iterator erase(iterator __position) {//擦除指定位置元素  
  103.     if (__position + 1 != end())  
  104.       copy(__position + 1, _M_finish, __position);//后续元素前移一位  
  105.     --_M_finish;  
  106.     destroy(_M_finish);//析构对象  
  107.     return __position;  
  108.   }  
  109.   iterator erase(iterator __first, iterator __last) {//擦除两个迭代器区间的元素  
  110.     iterator __i = copy(__last, _M_finish, __first);//把不擦除的元素前移  
  111.     destroy(__i, _M_finish);//析构对象  
  112.     _M_finish = _M_finish - (__last - __first);//调整finish的所指的位置  
  113.     return __first;  
  114.   }  
  115.   
  116.   void resize(size_type __new_size, const _Tp& __x) {//改变容器中可存储的元素个数,并不会分配新的空间  
  117.     if (__new_size < size()) //若调整后的内存空间比原来的小  
  118.       erase(begin() + __new_size, end());//擦除多余的元素  
  119.     else  
  120.       insert(end(), __new_size - size(), __x);//比原来多余的空间都赋予初值x  
  121.   }  
  122.   void resize(size_type __new_size) { resize(__new_size, _Tp()); }  
  123.   void clear() { erase(begin(), end()); }//清空容器  
  124.      // assign(), a generalized assignment member function.  Two  
  125.   // versions: one that takes a count, and one that takes a range.  
  126.   // The range version is a member template, so we dispatch on whether  
  127.   // or not the type is an integer.  
  128.   
  129.   /*该函数有两种类型: 
  130.     void assign( size_type count, const T& value ); 
  131.  
  132.     template< class InputIt > 
  133.     void assign( InputIt first, InputIt last ); 
  134.     */  
  135.   
  136.   //把容器内容替换为n个初始值为value  
  137.   void assign(size_type __n, const _Tp& __val) { _M_fill_assign(__n, __val); }  
  138.   void _M_fill_assign(size_type __n, const _Tp& __val);  
  139.   
  140. #ifdef __STL_MEMBER_TEMPLATES  
  141.     
  142.   template <class _InputIterator>  
  143.   void assign(_InputIterator __first, _InputIterator __last) {  
  144.     typedef typename _Is_integer<_InputIterator>::_Integral _Integral;  
  145.     _M_assign_dispatch(__first, __last, _Integral());  
  146.   }  
  147.   
  148.   template <class _Integer>  
  149.   void _M_assign_dispatch(_Integer __n, _Integer __val, __true_type)  
  150.     { _M_fill_assign((size_type) __n, (_Tp) __val); }  
  151.   
  152.   template <class _InputIter>  
  153.   void _M_assign_dispatch(_InputIter __first, _InputIter __last, __false_type)  
  154.     { _M_assign_aux(__first, __last, __ITERATOR_CATEGORY(__first)); }  
  155.   
  156.   template <class _InputIterator>  
  157.   void _M_assign_aux(_InputIterator __first, _InputIterator __last,  
  158.                      input_iterator_tag);  
  159.   
  160.   template <class _ForwardIterator>  
  161.   void _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last,  
  162.                      forward_iterator_tag);   
  163.   
  164. #endif /* __STL_MEMBER_TEMPLATES */  
      根据以上成员函数的注释,这里对其中几个函数进一步详细的讲解:iterator erase(iterator __first, iterator __last),void insert (iterator __pos, size_type __n, const _Tp& __x);

    其中擦除函数是擦除输入迭代器之间的元素,但是没有回收内存空间,只是把内存空间作为备用空间,首先看下该函数的源代码:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. iterator erase(iterator __first, iterator __last) {//擦除两个迭代器区间的元素  
  2.    iterator __i = copy(__last, _M_finish, __first);//把不擦除的元素前移  
  3.    destroy(__i, _M_finish);//析构对象  
  4.    _M_finish = _M_finish - (__last - __first);//调整finish的所指的位置  
  5.    return __first;  
  6.  }  
            根据上面函数的定义,我们可以知道,迭代器startend_of_storage并没有改变,只是调整迭代器finish,并析构待擦除元素对象;下面通过图解进行分析:


    插入元素函数是在指定位置position上连续插入n个初始值为x的元素,根据插入元素个数和可用空间大小的比较,分别进行不同的初始化,详细见源码分析:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1.   void insert (iterator __pos, size_type __n, const _Tp& __x)  
  2.     { //在pos位置连续插入n个初始值为x的元素  
  3.         _M_fill_insert(__pos, __n, __x); }  
  4.    
  5. template <class _Tp, class _Alloc>  
  6. void vector<_Tp, _Alloc>::_M_fill_insert(iterator __position, size_type __n,   
  7.                                          const _Tp& __x)  
  8. {  
  9.   if (__n != 0) {//当n不为0,插入才有效  
  10.     if (size_type(_M_end_of_storage - _M_finish) >= __n) {//若有足够的可用空间,即备用空间不小于新插入元素个数  
  11.       _Tp __x_copy = __x;  
  12.       const size_type __elems_after = _M_finish - __position;//计算插入点之后的现有元素个数  
  13.       iterator __old_finish = _M_finish;  
  14.   
  15.       //case1-a:插入点之后的现有元素个数大于新插入元素个数  
  16.       if (__elems_after > __n) {  
  17.         uninitialized_copy(_M_finish - __n, _M_finish, _M_finish);//把[finish-n,finish)之间的数据复制[finish,finish+n)  
  18.         _M_finish += __n;//调整迭代器finish所指的位置  
  19.         copy_backward(__position, __old_finish - __n, __old_finish);//把[position,old_finish-n)之间的数据复制[old_finish-n,old_finish)  
  20.         fill(__position, __position + __n, __x_copy);//在指定位置(插入点)填充初始值  
  21.       }  
  22.   
  23.       //case1-b:插入点之后的现有元素个数不大于新插入元素个数  
  24.       else {  
  25.         uninitialized_fill_n(_M_finish, __n - __elems_after, __x_copy);//先在可用空间填入n-elems_after个初始值x  
  26.         _M_finish += __n - __elems_after;//调整迭代器finish  
  27.         uninitialized_copy(__position, __old_finish, _M_finish);//把[position,old_finish)之间的数据复制到[old_finish,finish)  
  28.         _M_finish += __elems_after;  
  29.         fill(__position, __old_finish, __x_copy);  
  30.       }  
  31.     }  
  32.   
  33.     //case2:若备用空间小于新插入元素个数  
  34.     else {//若备用空间小于新插入元素个数,则分配新的空间  
  35.         //并把原始数据复制到新的空间,调整迭代器  
  36.       const size_type __old_size = size(); //获取原始空间的大小    
  37.       //新的空间为旧空间的两倍,或为旧空间+新增长元素个数  
  38.       const size_type __len = __old_size + max(__old_size, __n);  
  39.       //配置新的空间  
  40.       iterator __new_start = _M_allocate(__len);  
  41.       iterator __new_finish = __new_start;  
  42.       __STL_TRY {//把插入点之前的原始数据复制到新的空间  
  43.         __new_finish = uninitialized_copy(_M_start, __position, __new_start);  
  44.         //将新加入数据添加在[new_finish,new_finish+n)  
  45.         __new_finish = uninitialized_fill_n(__new_finish, __n, __x);  
  46.         //将插入点之后的原始数据复制到新空间  
  47.         __new_finish  
  48.           = uninitialized_copy(__position, _M_finish, __new_finish);  
  49.       }  
  50.       //释放原来空间的对象和内存  
  51.       __STL_UNWIND((destroy(__new_start,__new_finish),   
  52.                     _M_deallocate(__new_start,__len)));  
  53.       destroy(_M_start, _M_finish);  
  54.       _M_deallocate(_M_start, _M_end_of_storage - _M_start);  
  55.       //调整迭代器所指的位置  
  56.       _M_start = __new_start;  
  57.       _M_finish = __new_finish;  
  58.       _M_end_of_storage = __new_start + __len;  
  59.     }  
  60.   }  
  61. }  
    下面对不同情况利用图解方式对插入函数进行分析:

        case1-a:对应的源代码解析中的case1-a情况;



         case1-b:对应源码剖析中的case1-b情况:



       case2:针对源码剖析的case2情况:


0 0
原创粉丝点击