NashZhou

广告算法工程师,目前致力于关键词广告的效果自动优化

STL源码剖析读书笔记-第4章

第4章  序列式容器

容器是个大东西,还是带着问题分析好。

序列式容器里,我用的最多的还是vector。

1.我知道vector中有内存有预先分配,这种机制是好的,但有时候会浪费内存。

2.重点分析vector初始化大小,resize,erase等

vector容器

4.1.vector(n,v),使用这个构造函数可以指定含有n个v值的元素

看下源码:

构造函数
 1 /**
 2         *  @brief  Creates a %vector with copies of an exemplar element.
 3         *  @param  n  The number of elements to initially create.
 4         *  @param  value  An element to copy.
 5         *  @param  a  An allocator.
 6         *
 7         *  This constructor fills the %vector with @a n copies of @a value.
 8         */
 9        explicit
10        vector(size_type __n, const value_type& __value = value_type(),
11           const allocator_type& __a = allocator_type())
12        : _Base(__n, __a)
13        { _M_fill_initialize(__n, __value); }
14  
15        // Called by the first initialize_dispatch above and by the
16        // vector(n,value,a) constructor.
17        void
18        _M_fill_initialize(size_type __n, const value_type& __value)
19        {
20      std::__uninitialized_fill_n_a(this->_M_impl._M_start, __n, __value, 
21                        _M_get_Tp_allocator());
22      this->_M_impl._M_finish = this->_M_impl._M_end_of_storage;
23        }

最后一句this->_M_impl._M_finish = this->_M_impl._M_end_of_storage;

说明内存申请不会多不会少,刚刚好。

4.2.那么resize呢

看源码:

resize
 1 /**
 2        *  @brief  Resizes the %vector to the specified number of elements.
 3        *  @param  new_size  Number of elements the %vector should contain.
 4        *  @param  x  Data with which new elements should be populated.
 5        *
 6        *  This function will %resize the %vector to the specified
 7        *  number of elements.  If the number is smaller than the
 8        *  %vector's current size the %vector is truncated, otherwise
 9        *  the %vector is extended and new elements are populated with
10        *  given data.
11        */
12       void
13       resize(size_type __new_size, value_type __x = value_type())
14       {
15     if (__new_size < size())
16       _M_erase_at_end(this->_M_impl._M_start + __new_size);
17     else
18       insert(end(), __new_size - size(), __x);
19       }
20 //你懂的
21 void
22       clear()
23       { _M_erase_at_end(this->_M_impl._M_start); }
24 //insert有好多,别找错了
25  /**
26        *  @brief  Inserts a number of copies of given data into the %vector.
27        *  @param  position  An iterator into the %vector.
28        *  @param  n  Number of elements to be inserted.
29        *  @param  x  Data to be inserted.
30        *
31        *  This function will insert a specified number of copies of
32        *  the given data before the location specified by @a position.
33        *
34        *  Note that this kind of operation could be expensive for a
35        *  %vector and if it is frequently used the user should
36        *  consider using std::list.
37        */
38       void
39       insert(iterator __position, size_type __n, const value_type& __x)
40       { _M_fill_insert(__position, __n, __x); }

clear没有改变capacity这个大家都知道。所以resize小了,capacity也不会小掉。

里面的 Note that this kind of operation could be expensive for a
       *  %vector and if it is frequently used the user should
       *  consider using std::list.

值得玩味,如果能看到invert后start和finsh的指针位置发生改变,就可以证明_M_fill_insert有开辟新的空间。

这个_M_fill_insert(iterator __pos, size_type __n, const value_type& __x);

实现在vector.tcc里,比较复杂,就不深究了

4.3.push_back新增元素,如果vector中size==capacity,则会开辟一个双倍大小的连续新空间,将原来的数据拷贝过去,插入新元素。

给个小例子:

push_back
 1 #include <iostream>
 2 #include <vector>
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     int n = 16;
 8     vector<int> temp;
 9     for (int i = 1; i <= n; i ++)
10     {
11         cout << "before push, n: " << i << " capacity: " << temp.capacity() << endl;
12         temp.push_back(i);
13         cout << "after  push, n: " << i << " capacity: " << temp.capacity() << endl;
14     }
15     return 0;

 源码:

push_back
 1 /**
 2        *  @brief  Add data to the end of the %vector.
 3        *  @param  x  Data to be added.
 4        *
 5        *  This is a typical stack operation.  The function creates an
 6        *  element at the end of the %vector and assigns the given data
 7        *  to it.  Due to the nature of a %vector this operation can be
 8        *  done in constant time if the %vector has preallocated space
 9        *  available.
10        */
11       void
12       push_back(const value_type& __x)
13       {
14     if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
15       {
16         this->_M_impl.construct(this->_M_impl._M_finish, __x);
17         ++this->_M_impl._M_finish;
18       }
19     else
20       _M_insert_aux(end(), __x);
21       }

_M_insert_aux没找到实现,不过书上有。总之push_back慎用,还是resize在赋值好。

4.4.erase函数

erase
 1 template<typename _Tp, typename _Alloc>
 2     typename vector<_Tp, _Alloc>::iterator
 3     vector<_Tp, _Alloc>::
 4     erase(iterator __position)
 5     {
 6       if (__position + 1 != end())
 7     _GLIBCXX_MOVE3(__position + 1, end(), __position);
 8       --this->_M_impl._M_finish;
 9       this->_M_impl.destroy(this->_M_impl._M_finish);
10       return __position;
11     }

源码有点怪,反正要注意的是erase会返回一个iterator,指向被删除的下一个。

list容器

 list容器erase时只有被删除的那个iterator无效,其它的都有效,这点也在情理之中。其它的就不讲了。

deque容器

这个容器还真没用过,书上说deque由一段一段的定量连续空间构成。

一旦有必要在deque的前端或尾端增加新空间,便配置一段定量连续空间,

串接在整个deque的头端或尾端。deque的最大任务,

便是在这些分段的定量连续空间上,维护其整体连续的假象。

并提供随机存取的结果。避开了像Vector那样“重新配置,复制,释放”的轮回,

代价则是复杂的迭代器架构。具体细节以后用到再看,先略过。

stack容器

 stack是容器适配器,就是基于其它容器封装出来的。

默认stack用的是deque,我们可以用vectror,list指定。

比如 stack<int, vector<int> >,除此之外,stack不提供iterator。

queue容器

queue也不允许遍历,即不提供iterator。

queue也是容器适配器,默认基于deque构造。同样我们可以指定vector或list

 

posted on 2012-09-08 20:31  NashZhou  阅读(1304)  评论(0编辑  收藏  举报

导航