vector详解

引言

emmm…这篇博客写作的缘由其实就是我在日常使用vector的时候发现对vector并不怎么了解所以决定写这篇博客的。
写这篇博客,我参考了vector - C++ Reference中的内容,及侯捷先生的《STL源码剖析》一书,所实验的环境是CentOS7,g++4.8.5,所查看源码是SGI STL v3.3。这个版本的STL发布于2000年,而且是最新版。所以不包含C++11后的内容,所以遇到C++11后的内容我参考的是g++4.8.5中的STL。
另外就是这篇博客内容似乎比较多,阅读参考之类的最好通过目录来阅读….

vector简介

vector是表现为可变长数组的序列容器。
vector使用连续的存储位置来存储元素,也就是说,vector可以使用一个指针上的偏移量来访问其元素,就像数组一样。但与数组不同的是,它们的大小可以动态变化,其存储由容器自动处理。
在vector内部,使用一个动态分配内存的数组来保存其元素。当插入新元素的时候,这个数组可能需要重新分配,以增加大小,这意味着分配一个新的数组,并且将原有的元素从旧的位置移到新的数组中。这个操作在时间方面是个开销极大的操作,因此,vector不会每次新添加一个元素就重新分配内存。
相反,vector可能会分配一些额外的存储,以适应可能的增长,因此,vector可能具有一个比严格需求的存储size更大的capcity。不同的库可能采取不同的策略去平衡内存使用情况和内存分配,但是在任何情况下,重新分配内存应该只发生在大小的对数增长区间,以便在vector末尾插入单个元素的操作可以被提供均摊为常数时间的复杂度。
因此,vector相比于数组,vector消耗更多的内存,以换取管理存储和动态增长的能力。
与其它的动态序列容器(deque, lists, forward_lists)相比,vector可以非常高效的访问其元素,就像数组一样,并且可以相对高效的增加和删除元素从其末尾。对于在其它位置插入或删除元素的操作,它的性能要比其它的要差,而且其迭代器和引用的一致性相比lists和forward_lists要差。

以上摘自vector - C++ Reference

vector的定义

template<class T, class Alloc = alloc>
class vector {
public:
  typedef T           value_type;
  typedef value_type* pointer;
  typedef value_type* iterator;
  typedef value_type& 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;  // 表示目前可用空间的尾

  void insert_aux(iterator position, const T& x);
  void deallocate() {
    if (start) 
      data_allocator::deallocate(start, end_of_storage - start);
  }
  void fill_initialize(size_type n, const T& value) {
    start = allocate_and_fill(n, value);
    finish = start + n;
    end_of_storage = finish;
  }
public:
  iterator begin() { return start; }
  iterator end() { return finish; }
  size_type size() const { return size_type(end() - begin()); }
  size_type capcity() const {
    return size_type(end_of_storage - begin());
  }
  bool empty() const { return begin() == end(); }
  reference operator[](size_type n) { return *(begin() + n); }
  vector() : start(0), finish(0), end_of_storage(0) {}
  vector(size_type n, const T& value) { fill_initialize(n, value); }
  vector(int n, const T& value) { fill_initialize(n, value); }
  vector(long n, const T& value) { fill_initialize(n, value); }
  explicit vector(size_type n) { fill_initialize(n, T()); }
  ~vector() {
    destroy(start, finish);
    deallocate();
  }
  reference front() { return *begin(); } // 第一个元素
  reference back() { return *end(); } // 最后一个元素
  void push_back(const T& x) { // 将元素插入至最尾端
    if (finish != end_of_storage) {
      construct(finish, x);
      ++finish;
    } else insert_aux(end(), x);
  }
  void pop_back() { // 将最尾端元素取出
    --finish;
    destroy(finish);
  }
  iterator erase(iterator position) { // 清除某位置上的元素
    if (position + 1 != end()) 
      copy(position + 1, finish, position); // 后续元素往前移动
    --finish;
    destroy(finish);
    return position;
  }
  void resize(size_type new_size, const T& x) {
    if (new_size < size()) 
      erase(begin() + new_size, end());
    else
      insert(end(), new_size - size(), x);
  }
  void resize(size_type new size) { resize(new_size, T()); }
  void clear() { erase(begin(), end()); }
protected:
  // 配置空间并填满内容
  iterator allocate_and_fill(size_type n, const T& x) {
    iterator result = data_allocator::allocate(n);
    uninitialized_fill_n(result, n, x);
    return result;
  }
};

以上摘自侯捷先生的《STL源码剖析》,书上代码与SGI STL官网所下载代码相比,缺少很多C++11之后的内容,代码相对来说也进行了一定的简化。但是主体内容大致相同,比较好理解。
如果想了解最新的包含C++11之后内容的,可以看机械工业出版社出版的闫常友所写的《大道至简》,不过还是推荐侯捷先生这本《STL源码剖析》去了解STL。

vector使用及部分分析

构造函数

  • explicit vector(const allocator_type& alloc = allocator_type());
  • explicit vector(size_type n);
  • explicit vector(size_type n, const value_type& val, const allocator_type& alloc = allocator_type())
  • template <class InputIterator> vector (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type());
  • vector (const vector& x);
  • vector (const vector& x, const allocator_type& alloc);
  • vector (vector&& x);
  • vector (vector&& x, const allocator_type& alloc);
  • vector (initializer_list<value_type> il, const allocator_type& alloc = allocator_type());

前面几个都是普通的构造函数,值得一提的是最后一个,利用initializer_list来进行初始化。
test.cpp
result

析构函数

  • ~vector()

就是析构函数…没啥好说的

重载函数=

  • vector& operator= (const vector& x);
  • vector& operator= (vector&& x);
  • vector& operator= (initializer_list<value_type> il);

重载函数=依旧没什么好说的,就是正常的搞就行。值得说的是第二个重载函数,vector&& x 这个参数很迷啊,其实就是引用的引用而已,实现的就是移动构造函数,其实在上面构造函数就应该说的。这个方式可以提高效率,因为不需要创建一个新的vector对象,仅将一个vector的控制权交到了这个vector手上。我们可以从一个例子中证明:
test.cpp
其运行结果为:
result
从结果可见没有发生新的构造。

Iterator函数

vector的迭代器

vector的迭代器可以由定义可知,其本身是一个T*类型的指针。作为普通的指针,其本身具备的操作有:
- operator*
- operator->
- operator++
- operator--
- operator+
- operator-
- operator+=
- operator-=
具体使用方法,看下面的例子:
test.cpp
result

begin
  • iterator begin() noexcept;
  • const_iterator begin() const noexcept;

emmm…就是一个很普通的获取start位置的函数,可以参考前面源码。

end
  • iterator end() noexcept;
  • const_iterator end() const noexcept;

emmm…这个函数需要注意一下。它返回的是vector之后的一个被称为past_the_end的元素,这个元素是个虚拟的元素,它假装处于finish这个位置的后面一个位置。得到这个结果的主要原因就是C++在设置区间的时候一般都是左闭右开的区间,包含第一个位置而不包含最后一个位置。这个函数返回的iterator同样能够进行前面所说的*-+等运算。

rbegin
  • reverse_iterator rbegin() noexcept;
  • const_reverse_iterator rbegin() con
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值