SGI STL 源码 vector 分析

≡放荡痞女 提交于 2019-12-01 07:41:00

前言

vector 是最常用的 C++ 容器,其动态扩容的特性是普通数组无法具备的,大大增加了编程的灵活性。虽然能基本理解其基本原理,但也无法深层次理解,直到研读了 vector 的源码,才能比较自信的说自己真正理解了 vector 的基本原理,正应了侯捷说的那句话:源码面前,了无密码。我会分两篇文章分别分析泛化 vector 和针对 bool 类型的特化 vector(即是 bit_vector,位vector)。本文将分析泛化的 vector 的源码。

vector概述

vector 是动态扩容的连续数组。普通数组是静态空间,一旦配置就无法改变,而 vector 是动态空间,其内部机制会自动扩充空间以容纳更多的元素。其动态扩容的具体过程是:当容器没有备用空间时,会开辟一块是旧空间两倍大小的新空间,将数据从旧空间复制到新空间并释放原空间。因此,vector 对内存的合理利用和运用的灵活性有很大帮助,我没再也不用考虑数组的容量不足的问题。

vector 源码分析

本文分析的 vector 源码是侯捷老师《STL源码剖析》用的 SGI-STL-v2.91 的版本。其泛化版本的 vector 具体实现在 stl_vector.h 文件中,部分源码如下:

// alloc 是 SGI STL 的空间配置器
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;

#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION  //这里是反转迭代器,可先忽略
  typedef reverse_iterator<const_iterator> const_reverse_iterator;
  typedef reverse_iterator<iterator> reverse_iterator;
#endif

protected:
    // simple_alloc 是 SGI STL 的空间配置器,是源码所有容器都使用这个接口
    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; }
    const_iterator begin() const { return start; }
    iterator end() { return finish; }
    const_iterator end() const { return finish; }
    reverse_iterator rbegin() { return reverse_iterator(end()); }
    const_reverse_iterator rbegin() const {
        return const_reverse_iterator(end());
    }
    reverse_iterator rend() { return reverse_iterator(begin()); }
    const_reverse_iterator rend() const {
        return const_reverse_iterator(begin());
    }
    size_type size() const {
        return size_type(end() - begin());
    }
    size_type max_size() const {
        return size_type(-1) / sizeof(T);
    }
    size_type capacity() const {
        return size_type(end_of_storage - begin());
    }
    bool empty() const { return begin() == end(); }

    reference operator[](size_type n) {
        return *(begin() + n);
    }
    const_reference operator[](size_type n) const {
        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(const vector<T, Alloc>& x) {
        start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
        finish = start + (x.end() - x.begin());
        end_of_storage = finish;
    }
    template <class InputIterator>
    vector(InputIterator first, InputIterator last) :
        start(0), finish(0), end_of_storage(0)
    {
        range_initialize(first, last, iterator_category(first));
    }

    ~vector() {
        destroy(start, finish);  //全局变量
        deallocate();
    }

    vector<T, Alloc>& operator=(const vector<T, Alloc>& x);

    void reverve(size_type n) {
        if (capacity() < n) {
            const size_type old_size = size();
            iterator tmp = allocate_and_copy(n, start, finish);
            destroy(start, finish);
            deallocate();
            start = tmp;
            finish = start + old_size;
            end_of_storage = start + n;
        }
    }

    reference front() { return *begin(); }
    const_reference front() const { return *begin(); }
    reference back() { return *(end() - 1); }
    const_reference back() const { return *(end() - 1); }

    void push_back(const T& x) {
        if (finish != end_of_storage) {  //还有备用空间
            construct(finish, x);  //全局函数
            ++finish;
        } else  //无备用空间
            insert_aux(end(), x);  //成员函数,后续会分析
    }

    void swap(vector<T, Alloc>& x) {
        __STD::swap(start, x.start);
        __STD::swap(finish, x.finish);
        __STD::swap(end_of_storage, x.end_of_storage);
    }
    
    //和push_back差别不大,只是插入位置不一样,复杂一点
    iterator insert(iterator position, const T& x) {  
        size_type n = position - begin();
        if (finish != end_of_storage && position == end()) {
            construct(finish, x);
        } else 
            insert_aux(position, x);

        return begin() + n;
    }
    
    iterator insert(iterator position) {
        insert(position, T());
    }

    #ifdef __STL_MEMBER_TEMPLATES
    template <class InputIterator>
    void insert(iterator position, InputIterator first, InputIterator last) 
    {
        range_insert(position, first, last, iterator_category(first));
    }
    #endif

    void insert(iterator pos, size_type n, const T& x);

    void insert(iterator pos, int n, const T& x) {
        insert(pos, (size_type) n, x);
    }
    
    void insert(iterator pos, long n, const T& x) {
        insert(pos, (size_type) n, x);
    }

    void pop_back() {
        --finish;
        destroy(finish);    //finish->~T 这里仅仅是调用指针finish所指对象的析构函数,不能释放内存
    }
  
    iterator erase(iterator position) {
        //如果移除的不是最后一个元素
        if (position + 1 != end())
            copy(position + 1, finish, position);  //全局函数

        --finish;
        destroy(finish);
        return position;
    }

    //移除半开半闭区间[first, last)之间的所有元素,last指向的元素不被移除
    iterator erase(iterator first, iterator last) {
        iterator i = copy(last, finish, first);  
        //如果区间内元素的析构函数是trivial的,则什么也不做
        //如果区间内元素的析构函数是non-trivial的,则依序调用其析构函数
        destroy(i, finish);    
        finish = finish - (last - first);    //重新调整finish
        return first;
    }
    
    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);
        __STL_TRY 
        {
            uninitialized_fill_n(result, n, x);
            return result;
        }
        __STL_UNWIND(data_allocator::deallocate(result, n));
    }
      template <class ForwardIterator>
      iterator allocate_and_copy(size_type n,
                                 ForwardIterator first, ForwardIterator last) {
          iterator result = data_allocator::allocate(n);
          __STL_TRY {
              uninitialized_copy(first, last, result);
              return result;
          }
          __STL_UNWIND(data_allocator::deallocate(result, n));
      }
/***********************后续还有********************************/

 

 

vector 迭代器

vector 维护的是一个连续空间所以无论其元素的型别为何,普通指针就可以作为 vector 的迭代器而满足所有必要条件,因为 vector 迭代器所需要的操作行为,如 operator*,operator++,operator--,operator+,operator-,operator+=,operator-=,普通指针就具备,从上面的源码就可以看出,vector 用的迭代器就是普通指针。但除 bool 类型,虽然普通指针一样适用,为提高空间利用率,源码为其设计的特化版本有设计专门的迭代器,下一篇文件会进一步探讨。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!