STL——vector模拟实现

在学习过程种 ,学习看源码是很有必要的,它可以让你更清楚的知道一些代码的细节,你也会发现源码将效率利用到了极致,不得不佩服写出源码的人。

下面我将配合源码来实现一个简单的vector,下面请看源码

看源码我们首先要看的就是成员变量,我们可以看到源码中有迭代器的start、finish、end_of_storage三个成员变量,然后可以看到它将一些类型进行重命名。我们可以将它理解为下面的这张图。


其次我们接下来看它的构造函数,它提供了无参和带参的构造函数,看到有fill_initialize这个函数,不难猜一猜可能和初始化有关。这里就不将它展开说了,有兴趣的可以去看看《STL源码剖析》这本书。

学习了vector,可以知道resize是一个改变vector的finish

  • 如果传入new_size比有效元素少,就将后面的元素删除
  • 如果传入的new_size比有效元素多,那么就在最后加上x

与resize相对应的就是reserve函数了,它是改变vector的end_of_storage

  • 如果开辟的容量大于end_of_storage,那么就开辟一个n个空间的大小
  • 然后将数据拷贝到新空间中,然后将旧空间释放掉
  • 最后改变start的指向

但是这里注意一下,当发生数据拷贝的时候,是不能直接进行memcpy,要知道vector中存放的是一个T类型,如果T是string,那么当发生memcpy的时候就会发生浅拷贝,里面string指向的是一块释放了的空间。

接下来我们看一下insert函数

  • 关于insert,首先我们要知道当进行插入操作时就有可能触发扩容,那么就有可能触发reserve函数,那么就有可能空间释放的问题,所以不能memmove。

所以,了解了一些特殊情况,就可以实现了。

template <class T>
  class vector
  {
  public:
    typedef T* iterator;
    typedef const T* const_iterator;

    vector()
        : start(nullptr), finish(nullptr), end_of_storage(nullptr)
    {
    }

    vector(size_t n, const T &value)
    {
      push_back(value);
    }

    explicit vector(size_t n)
    {
      for (int i = 0; i < n; i++)
      {
        push_back(T());
      }
    }

    template<class InputIterator>
    vector(InputIterator first,InputIterator last)
    {
      while(first != last)
      {
        push_back(*first);
        ++first;
      }
    }

    vector(int n, const T &value = T())
    {
      resize(n, value);
    }

    vector(long n, const T &value = T())
    {
      resize(n, value);
    }

    // v2(v1)
    vector(const vector<T> &v)
    {
      reserve(v.capacity());
      for (auto e : v)
      {
        push_back(e);
      }
    }
    
    //v2 = v1
    vector<T>& operator=(vector<T> v)
    {
      swap(v);

      return *this;
    }

      ~vector()
    {
      if (start)
      {
        delete[] start;

        start = finish = end_of_storage = nullptr;
      }
    }

    iterator begin()
    {
      return start;
    }

    const_iterator begin() const 
    {
      return start;
    }

    iterator end()
    {
      return finish;
    }

    const_iterator end() const 
    {
      return finish;
    }

    size_t size() const
    {
      return finish - start;
    }

    size_t max_size() const
    {
      return size_t(-1) / sizeof(T);
    }

    bool empty() const 
    {
      return start == finish;
    }

    void swap(vector<T> &v)
    {
      ::swap(start, v.start);
      ::swap(finish, v.finish);
      ::swap(end_of_storage, v.end_of_storage);
    }

    void resize(size_t n, T val = T())
    {
      // 如果n > size()就开空间,将val插入到后面
      if (n > size())
      {
        reserve(n);
        while (finish < start + n)
        {
          *finish = val;
          ++finish;
        }
      }
      else
      {
        // 将有效空间变小
        finish = start + n;
      }
    }

    void reserve(size_t n)
    {
      if (n > capacity())
      {
        size_t old = size();
        // 申请新空间
        T *tmp = new T[n];
        if (start)
        {
          // memcpy(tmp,start,sizeof(T)*old);
          // 之所以不能用memcpy,是因为如果是自定义类型,深拷贝的时候就会访问释放了的空间了
          // 当然,这里可以用引用计数或者移动构造、移动赋值来搞定这个问题。
          for (size_t i = 0; i < old; i++)
          {
            tmp[i] = start[i];
          }

          delete[] start;
        }

        start = tmp;
        finish = start + old;
        end_of_storage = start + n;
      }
    }

    size_t capacity() const
    {
      return end_of_storage - begin();
    }

    void push_back(const T &x)
    {
      if (finish != end_of_storage)
      {
        *finish = x;
        ++finish;
      }
      else
      {
        size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
        reserve(newcapacity);

        *finish = x;
        ++finish;
      }
    }

    void pop_back()
    {
      assert(size() > 0);

      --finish;
    }

    iterator erase(iterator pos)
    {
      assert(pos >= start);
      assert(pos < finish);

      // 将pos之后的元素从后往前移动
      iterator it = pos + 1;
      while (it < finish)
      {
        *pos = *it;
        it++;
      }

      --finish;

      return pos;
    }

    iterator insert(iterator pos,const T& x)
    {
      assert(pos <= finish && pos >= start);

      if(finish == end_of_storage)
      {
        size_t len = pos - start;
        reserve(capacity() == 0 ? 4 : 2*capacity());
        pos = start + len;
      }

      iterator  end = finish;
      while(pos < end)
      {
        *end = *(end-1);
        --end;
      }

      *pos = x;
      ++finish;
    
      return pos;
    }

    T &operator[](size_t n)
    {
      assert(n <= size());

      return *(begin() + n);
    }

    const T &operator[](size_t pos) const 
    {
      assert(pos >= start);
      assert(pos < finish);

      return start[pos];
    }


  private:
    iterator start = nullptr;
    iterator finish = nullptr;
    iterator end_of_storage = nullptr;
  };

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值