首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

stl vector源码剖析

  • 25-03-02 17:02
  • 4438
  • 5027
blog.csdn.net

前言

     项目组要实现一个算法库,其中涉及到了类似vector的一维数组的实现。特此,对stl中得vector做个学习和了解。有任何问题,欢迎不吝指正。谢谢。

一、如何实现vector   

     如果给你一道面试题,如何用数据结构实现STL中vector的功能?聪明的你会怎么做呢?或许你会如下所述:

  • 或许,如果不考虑分配效率,只需要两个成员就可以实现了
    template
    class   Vector
    {
    public:
            Vector(int   nLen=0):m_nLen(nLen),m_Data(NULL)
            {
                    if(nLen   >   0)
                    {
                            m_Data   =   new   _Ty[nLen];
                    }
            }
    protected:
            _Ty   *   m_Data;
            int       m_nLen;
    };
  • 或许,如下一个简单的思路实现:

    #include  

    using   std::ostream;
    using   std::istream;

    class   Array   {
          friend   ostream   &operator < <(   ostream   &,   const   Array   &   );
          friend   istream   &operator> > (   istream   &,   Array   &   );

    public:
          Array(   int   =   10   );            
          Array(   const   Array   &   );  
          ~Array();                              
          int   getSize()   const;          

          const   Array   &operator=(   const   Array   &   );  
          bool   operator==(   const   Array   &   )   const;    

          bool   operator!=(   const   Array   &right   )   const    
          {  
                return   !   (   *this   ==   right   );  
         
          }  
         
          int   &operator[](   int   );                            
          const   int   &operator[](   int   )   const;    
         
    private:
          int   size;  
          int   *ptr;  

    };
  • 或许你会说,应该用模板写。当数组大小变化时,就直接new   当前大小,将旧有的或拷贝或加入新的东西加入,然后删除旧有的m_pData;并更新m_nLen;
    当数据大小不变化时,直接使用m_pData;。如果考虑分配效率,则还需要一个成员存储m_nMaxLen;实际的分配大小。 要记住一定删除旧的m_pData就可以。

    很快,你就会意识到,与其这样不知方向的摸着石头过河,不如直接拿来stl里的vector实现代码,来瞧个究竟。ok,下面,咱们来剖析下stl vector的实现。其中的分析借助了侯捷先生的stl源码剖析(大凡研究sgi stl源码,此书都不容忽略),然后再加入一些自己的理解。希望对你有所帮助(下面咱们分析的版本是sgi stl v2.9版)。

二、vector的类定义

    以下是vector定义的类中的一些数据成员和部分成员函数:

  1. template <class T, class Alloc = alloc> // 预设使用 alloc 为配置器
  2. class vector {
  3. public:
  4. // 以下标示 (1),(2),(3),(4),(5),代表 iterator_traits 所服务的5個型别。
  5. typedef T value_type; // (1)
  6. typedef value_type* pointer; // (2)
  7. typedef const value_type* const_pointer;
  8. typedef const value_type* const_iterator;
  9. typedef value_type& reference; // (3)
  10. typedef const value_type& const_reference;
  11. typedef size_t size_type;
  12. typedef ptrdiff_t difference_type; // (4)
  13. // 以下,由于vector 所维护的是一个连续线性空間,所以不论其元素型別为何,
  14. // 原生指标都可以做为其迭代器而满足所有需求。
  15. typedef value_type* iterator;
  16. /* 根据上述写法,如果客户端写出如下的代码:
  17. vector::iterator is;
  18. is 的型別其实就是Shape*
  19. 而STL 內部运用 iterator_traits::reference 时,获得 Shape&
  20. 运用iterator_traits::iterator_category 时,获得
  21. random_access_iterator_tag (5)
  22. (此乃iterator_traits 针对原生指标的特化结果)
  23. */
  24. //此处省略了一些与本文主题相关性不大的内容.......
  25. protected:
  26. // 专属之空间配置器,每次配置一個元素大小
  27. typedef simple_alloc data_allocator;
  28. // vector采用简单的连续线性空间。以两个迭代器start和end分別指向头尾,
  29. // 并以迭代器end_of_storage指向容量尾端。容量可能比(尾-头)还大,
  30. // 多余即借用空間。
  31. iterator start; //表示目前使用空间的头
  32. iterator finish; //表示目前使用空间的尾
  33. iterator end_of_storage; //表示目前可用空间的尾
  34. void insert_aux(iterator position, const T& x);
  35. void deallocate() {
  36. if (start)
  37. data_allocator::deallocate(start, end_of_storage - start);
  38. }
  39. void fill_initialize(size_type n, const T& value) {
  40. start = allocate_and_fill(n, value); // 配置空间并设初值
  41. finish = start + n; // 调整水位
  42. end_of_storage = finish; // 调整水位
  43. }

  下面是另外一些成员操作函数的具体实现,

  1. public:
  2. iterator begin() { return start; }
  3. const_iterator begin() const { return start; }
  4. iterator end() { return finish; }
  5. const_iterator end() const { return finish; }
  6. reverse_iterator rbegin() { return reverse_iterator(end()); }
  7. const_reverse_iterator rbegin() const {
  8. return const_reverse_iterator(end());
  9. }
  10. reverse_iterator rend() { return reverse_iterator(begin()); }
  11. const_reverse_iterator rend() const {
  12. return const_reverse_iterator(begin());
  13. }
  14. size_type size() const { return size_type(end() - begin()); }
  15. size_type max_size() const { return size_type(-1) / sizeof(T); }
  16. size_type capacity() const { return size_type(end_of_storage - begin()); }
  17. bool empty() const { return begin() == end(); }
  18. reference operator[](size_type n) { return *(begin() + n); }
  19. const_reference operator[](size_type n) const { return *(begin() + n); }
  20. vector() : start(0), finish(0), end_of_storage(0) {}
  21. // 以下建模式,允許指定大小 n 和初值 value
  22. vector(size_type n, const T& value) { fill_initialize(n, value); }
  23. vector(int n, const T& value) { fill_initialize(n, value); }
  24. vector(long n, const T& value) { fill_initialize(n, value); }
  25. explicit vector(size_type n) { fill_initialize(n, T()); }
  26. vector(const vector& x) {
  27. start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
  28. finish = start + (x.end() - x.begin());
  29. end_of_storage = finish;
  30. }
  31. template <class InputIterator>
  32. vector(InputIterator first, InputIterator last) :
  33. start(0), finish(0), end_of_storage(0)
  34. {
  35. range_initialize(first, last, iterator_category(first));
  36. }
  37. vector(const_iterator first, const_iterator last) {
  38. size_type n = 0;
  39. distance(first, last, n);
  40. start = allocate_and_copy(n, first, last);
  41. finish = start + n;
  42. end_of_storage = finish;
  43. }
  44. #endif /* __STL_MEMBER_TEMPLATES */
  45. ~vector() {
  46. destroy(start, finish); // 全域函式,建构/解构基本工具。
  47. deallocate(); // 先前定义好的成员函式
  48. }
  49. vector& operator=(const vector& x);
  50. void reserve(size_type n) {
  51. if (capacity() < n) {
  52. const size_type old_size = size();
  53. iterator tmp = allocate_and_copy(n, start, finish);
  54. destroy(start, finish);
  55. deallocate();
  56. start = tmp;
  57. finish = tmp + old_size;
  58. end_of_storage = start + n;
  59. }
  60. }

三、vector中insert的实现    

    纷纷扰扰的细节,咱们一概忽略,最后,咱们来具体分析vector中insert(插入)一个元素的实现:

  1. // 從 position 开始,安插 n 個元素,元素初值为 x
  2. template <class T, class Alloc>
  3. void vector::insert(iterator position, size_type n, const T& x) {
  4. if (n != 0) { // 当 n != 0 才進行以下所有动作
  5. if (size_type(end_of_storage - finish) >= n) {
  6. // 借用空间大于等于 「新增元素个数」
  7. T x_copy = x;
  8. // 以下計算插入点之后的现有元素个数
  9. const size_type elems_after = finish - position;
  10. iterator old_finish = finish;
  11. if (elems_after > n) {
  12. // 「插入点之后的现有元素个数」大于「新增元素个数」
  13. uninitialized_copy(finish - n, finish, finish); //finish-n:整体后移
  14. finish += n; //将vector 尾端标记后移
  15. copy_backward(position, old_finish - n, old_finish); //插入点元素A后移至A‘,position->old—finish后移至old_finish
  16. fill(position, position + n, x_copy); // 从插入点开始填入新值
  17. }
  18. else {
  19. // 「插入点之后的现有元素个数」小于等于「新增元素个数」
  20. uninitialized_fill_n(finish, n - elems_after, x_copy); //1.新增元素x_copy插入至finish处
  21. finish += n - elems_after; //2.finish后移n_elems_after
  22. uninitialized_copy(position, old_finish, finish); //3.腾出空间,position->old_finish
  23. finish += elems_after; //4.finish再次后移
  24. fill(position, old_finish, x_copy); //5.插入新元素,(x_copy)position->old_finish
  25. }
  26. }
  27. else {
  28. // 借用空間小于「新增元素个数」(那就必须配置额外的内存)
  29. // 首先決定新长度:旧长度的兩倍,或旧长度+新增元素个数。
  30. const size_type old_size = size();
  31. const size_type len = old_size + max(old_size, n);
  32. // 以下配置新的vector 空間
  33. iterator new_start = data_allocator::allocate(len);
  34. iterator new_finish = new_start;
  35. __STL_TRY {
  36. // 以下首先将旧vector 的插入点之前的元素复制到新空间。
  37. new_finish = uninitialized_copy(start, position, new_start);
  38. // 以下再将新增元素(初值皆为n)填入新空间。
  39. new_finish = uninitialized_fill_n(new_finish, n, x);
  40. // 以下再將旧vector 的插入点之后的元素复制到新空间。
  41. new_finish = uninitialized_copy(position, finish, new_finish);
  42. }
  43. # ifdef __STL_USE_EXCEPTIONS
  44. catch(...) {
  45. // 如有异常发生,实现 "commit or rollback" semantics.
  46. destroy(new_start, new_finish);
  47. data_allocator::deallocate(new_start, len);
  48. throw;
  49. }
  50. # endif /* __STL_USE_EXCEPTIONS */
  51. // 以下清除并释放旧的 vector
  52. destroy(start, finish);
  53. deallocate();
  54. // 以下調整水位标记
  55. start = new_start;
  56. finish = new_finish;
  57. end_of_storage = new_start + len;
  58. }
  59. }
  60. }

    我想,如果本文只是单单给出上面的代码,你一定内心非常愤懑,道:晕,又是一篇什么鬼剖析,就一大堆代码加注释,看上去就是一堆乱码,有什么意思嘛。是的,我想,读者肯定并没有看懂上述insert的实现,那么,下面,请允许我引用stl源码剖析一书里面的三张图片,相信,看过图片之后,您就会对vector中insert的实现清晰不少了:

    如下图4-3b-1所示的情况是,备用空间为2,新增元素也为2,所以,备用空间>=新增元素个数,而插入点之后的元素个数为3大于新增元素个数2(原有元素个数3个+备用空间为2,共5个存储单位)。此种情况的处理方式是,相当于将插入点之后的原有的3个元素整体向后移2个单位,然后把要新增的2个元素从插入点处插入,刚好满足新增的2个元素加上原有的3个元素共同存储在5个单位的空间中。

 

    如下图4-3b-2所示,插入点之后的现有元素个数2<=新增元素个数3,此种情况的处理方式为:相当于将插入点之后的原有的3个元素整体向后移三个单位,然后把新增的3个元素从原插入点处插入:

    如果原有空间不够,那么vector将实施所谓的动态增加大小,而动态增加大小,并不是指在原空间之后接连续新空间(因为无法保证原空间之后尚有可供配置的空间),而是以原大小的两倍另外配置一块较大空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间,这点可以从上述insert的实现中的第二部分,当借用空間小于「新增元素個數」(那就必须配置额外的内存)可以看出来。

    如下图4-3b-3所示(另外,必须提醒的是,经过上述操作后,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了。这是一般人会犯的错误,务必小心。 --侯捷如是说):

四、vector的扩展

    最后,我再贴一段代码,相当于是vector的高效应用(或者说是拓展):

  1. /*
  2. Copyright (c) 2007-2011 iMatix Corporation
  3. Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file
  4. This file is part of 0MQ.
  5. 0MQ is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. 0MQ is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with this program. If not, see < http://www.gnu.org/licenses/>.
  15. */
  16. #ifndef __ZMQ_ARRAY_INCLUDED__
  17. #define __ZMQ_ARRAY_INCLUDED__
  18. #include
  19. #include
  20. //w++
  21. //从个人风格上来讲,一般要拒绝这种类中成员函数全部内联的用法。
  22. namespace zmq
  23. {
  24. // Base class for objects stored in the array. Note that each object can
  25. // be stored in at most one array.
  26. class array_item_t
  27. {
  28. public:
  29. inline array_item_t () :
  30. array_index (-1)
  31. {
  32. }
  33. // The destructor doesn't have to be virtual. It is mad virtual
  34. // just to keep ICC and code checking tools from complaining.
  35. inline virtual ~array_item_t ()
  36. {
  37. }
  38. inline void set_array_index (int index_)
  39. {
  40. array_index = index_;
  41. }
  42. inline int get_array_index ()
  43. {
  44. return array_index;
  45. }
  46. private:
  47. int array_index;
  48. array_item_t (const array_item_t&);
  49. const array_item_t &operator = (const array_item_t&);
  50. };
  51. // stl vector是一种简单高效的容器,在尾端插入和删除元素,算法时间复杂度为O(1)常数阶,其他元素的插入和删除为O(n)线性阶,
  52. // 其中n为vector容器的元素个数。vector具有自动的内存管理功能,对于元素的插入和删除,可动态调整所占用的内存空间。
  53. // Fast array implementation with O(1) access to item, insertion and
  54. // removal. Array stores pointers rather than objects. The objects have
  55. // to be derived from array_item_t class.
  56. template <typename T> class array_t
  57. {
  58. public:
  59. typedef typename std::vector ::size_type size_type;
  60. inline array_t ()
  61. {
  62. }
  63. inline ~array_t ()
  64. {
  65. }
  66. inline size_type size ()
  67. {
  68. return items.size ();
  69. }
  70. inline bool empty ()
  71. {
  72. return items.empty ();
  73. }
  74. inline T *&operator [] (size_type index_)
  75. {
  76. return items [index_];
  77. }
  78. inline void push_back (T *item_)
  79. {
  80. if (item_)
  81. item_->set_array_index (items.size ());
  82. items.push_back (item_);
  83. }
  84. inline void erase (T *item_) {
  85. erase (item_->get_array_index ());
  86. }
  87. inline void erase (size_type index_) {
  88. if (items.back ())//back函数返回最末一个元素的引用
  89. items.back ()->set_array_index (index_);
  90. items [index_] = items.back ();
  91. items.pop_back ();
  92. }
  93. inline void swap (size_type index1_, size_type index2_)
  94. {
  95. //交换序号和内容
  96. if (items [index1_])
  97. items [index1_]->set_array_index (index2_);
  98. if (items [index2_])
  99. items [index2_]->set_array_index (index1_);
  100. std::swap (items [index1_], items [index2_]);
  101. }
  102. inline void clear ()
  103. {
  104. items.clear ();
  105. }
  106. inline size_type index (T *item_)
  107. {
  108. return (size_type) item_->get_array_index ();
  109. }
  110. private:
  111. typedef std::vector items_t;
  112. items_t items;
  113. array_t (const array_t&);
  114. const array_t &operator = (const array_t&);
  115. };
  116. }
  117. #endif

    说明:@555,在webkit中的WTF模块中,它里面的vector是直接放弃了STL的vector,它是利用google的tcmalloc来管理内存的,比stl的高效。

    参考:侯捷先生的stl源码剖析。

    ok,如果有任何问题,欢迎不吝指正。完。

注:本文转载自blog.csdn.net的v_JULY_v的文章"http://blog.csdn.net/v_july_v/article/details/6681522"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top