STL源码剖析(4):容器(vector)

来源:互联网 发布:查看淘宝店铺数据 编辑:程序博客网 时间:2024/05/29 09:06

  容器是很多人对STL的第一印象,vector,stack,queue,set,map等等都是容器。
  这里先介绍 STL中的序列式容器。
  所谓序列式容器,其中的元素可序(ordered),但未必有序(sorted)。C++ 本身提供了一个序列式容器——数组(array),STL中还提供了向量(vector),链表(list),堆栈(stack),队列(queue),优先队列(priority queue)等,其中stack和queue只是将deque(双端队列)设限而得到的,技术上可以被归为一种配接器(adaptor)。

Vector:
  vector的数据安排以及操作方式与array非常相似,两者的唯一差别在于空间的运用的灵活性。array是静态空间,一旦配置了就不能改变。vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。因此,vector对内存的运用更加有效,更加有效。Vector的实现技术,关键是对大小的控制以及重新配置时的数据移动效率,主要分为三个步骤:配置新空间,数据移动,释放旧空间。
  Vector内部结构为:

template <class T, class Alloc = alloc>class vector {public:  typedef T value_type;  typedef value_type* pointer;  typedef const value_type* const_pointer;  typedef value_type* iterator;  typedef const value_type* const_iterator;  typedef value_type& reference;  typedef const value_type& const_reference;  typedef size_t size_type;  typedef ptrdiff_t difference_type;protected:  typedef simple_alloc<value_type, Alloc> data_allocator;  iterator start;  iterator finish;  iterator end_of_storage;};

  vector使用的线性连续空间,其中start是目前使用空间的头,finish是目前使用空间的为尾,end_of_storage是可使用空间的尾。为了降低空间配置时的速度成本,vector实际配置的大小可能比目前vector存储的数据所需的空间要大,以备将来的扩充。如果满载并有新元素加入,就另觅新居。
  vector维护的是一个连续线性空间,所以无论其元素型别为何,普通指针都可以作为vector的迭代器。因为vector迭代器所执行的操作行为,如operator*,operator->,operator++,operator–,operator+,operator-,operator+=,operator-=,普通指针天生就具备。所以,vector提供的是Random Access Iterator。
  vector若空间不够,在动态增长时,并不是在原来空间之后接续新空间,而是以原大小的两倍配置一块较大空间,然后将原内容拷贝过来。因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。
 
  来看下vector几个常用操作的源码:

void push_back(const T& x) {    if (finish != end_of_storage) { //空间未满      construct(finish, x); //直接构造      ++finish;    }    else //空间不够      insert_aux(end(), x);}iterator insert(iterator position, const T& x) {    size_type n = position - begin();    if (finish != end_of_storage && position == end()) { //空间未满且在末尾插入      construct(finish, x);      ++finish;    }    else      insert_aux(position, x);    return begin() + n;  }  void pop_back() {    --finish;    destroy(finish); //析构}template <class T, class Alloc>void vector<T, Alloc>::insert_aux(iterator position, const T& x) {  if (finish != end_of_storage) { //空间未满    construct(finish, *(finish - 1)); //插入要增加一个元素,所以先在末尾新构造一个    ++finish;    T x_copy = x;    copy_backward(position, finish - 2, finish - 1); //从position往后移动一个位置    *position = x_copy; //插入  }  else {    const size_type old_size = size(); //当前的空间大小    const size_type len = old_size != 0 ? 2 * old_size : 1; //新的空间大小,为以前的两倍    iterator new_start = data_allocator::allocate(len);//分配新的空间    iterator new_finish = new_start;    __STL_TRY {      new_finish = uninitialized_copy(start, position, new_start); //复制position之前的数据      construct(new_finish, x); //插入新元素      ++new_finish;      new_finish = uninitialized_copy(position, finish, new_finish); //复制position之后的数据    }    destroy(begin(), end());//析构原来的元素    deallocate();//释放原来的空间    start = new_start;    finish = new_finish;    end_of_storage = new_start + len;  }}

  其中copy_backward()代码如下:

template <class BidirectionalIterator1, class BidirectionalIterator2>inline BidirectionalIterator2 __copy_backward(BidirectionalIterator1 first,                                               BidirectionalIterator1 last,                                               BidirectionalIterator2 result) {  while (first != last) *--result = *--last;  return result;}

其他常见操作:
Iterators:
begin:Return iterator to beginning (public member function )
end:Return iterator to end (public member function )

Capacity:
size:Return size (public member function )
capacity:Return size of allocated storage capacity (public member function )
empty:Test whether vector is empty (public member function )

Element access:
operator[]:Access element (public member function )
at:Access element (public member function )
front:Access first element (public member function )
back:Access last element (public member function )
data:Access data (public member function )

Modifiers:
push_back:Add element at the end (public member function )
pop_back:Delete last element (public member function )
insert:Insert elements (public member function )
erase:Erase elements (public member function )
swap:Swap content (public member function )
clear:Clear content (public member function )
emplace :Construct and insert element (public member function )
emplace_back :Construct and insert element at the end (public member function )

0 0