C++初阶之一篇文章让你掌握vector(模拟实现)(下)

简介: 3.4.3 增删查改函数push_back()

3.4.3 增删查改函数

push_back()

void push_back(const T& x)
{
    if (_finish == _end_of_storage)
    {
      reserve(capacity() == 0 ? 4 : capacity() * 2);
    }
    *_finish = x;
    ++_finish;
    //insert(end(), x);
}

首先,函数检查 _finish 指针是否等于 _end_of_storage,即是否达到了当前容器的容量上限。如果达到了容量上限,说明没有足够的空间存放新元素,因此需要进行内存重新分配

内存重新分配时,使用 reserve 函数,如果当前容量为 0,则分配至少 4 个元素的空间,否则将容量扩展为当前容量的两倍。然后,函数将新元素 x 赋值给 _finish 指针指向的位置,即当前容器的末尾。然后,通过递增 _finish 指针,将 _finish 指向下一个可用位置

pop_back()

void pop_back()
{
  assert(_finish > _start);
  --_finish;
}

首先,函数使用 assert 宏来检查 _finish 指针是否大于 _start 指针。这是一个断言,用于确保在 _finish 小于或等于 _start 时不会发生错误。如果 _finish 不大于 _start,则断言会触发错误,帮助在开发过程中发现问题。

接着,函数将 _finish 指针递减 1,从而使其指向容器中的倒数第二个元素,即删除了最后一个元素

iterator insert()

iterator insert(iterator pos, const T& x)
{
  assert(pos >= _start);
  assert(pos <= _finish);
  if (_finish == _end_of_storage)
  {
    size_t len = pos - _start;
    reserve(capacity() == 0 ? 4 : capacity() * 2);
    pos = _start + len;
  }
  // 挪动数据
  iterator end = _finish - 1;
  while (end >= pos)
  {
    *(end + 1) = *end;
    --end;
  }
  *pos = x;
  ++_finish;
  return pos;
}

首先,函数使用 assert 宏来检查 pos 是否在 _start 和 _finish 之间,确保插入位置在合法范围内。然后,函数检查容器是否已满,即 _finish 是否等于 _end_of_storage。如果容器已满,需要扩容。首先计算插入位置相对于 _start 的偏移量 len,以便在插入后重新定位 pos,以防扩容导致迭代器失效。接着根据扩容规则进行扩容操作,将 _start 移动到新分配的内存中。在容器中插入元素之前,需要将插入位置之后的元素往后挪动一个位置。使用一个循环从 _finish - 1 开始,逐个将元素向后移动一位,为新元素腾出空间。将新元素 x 插入到指定的位置 pos。最后,递增 _finish 指针,表示容器中多了一个元素,然后返回插入位置的迭代器

iterator erase()

iterator erase(iterator pos)
{
  assert(pos >= _start);
  assert(pos < _finish);
  iterator begin = pos + 1;
  while (begin < _finish)
  {
    *(begin - 1) = *begin;
    ++begin;
  }
  --_finish;
  return pos;
}

首先,函数使用 assert 宏来检查 pos 是否在 _start 和 _finish 之间,确保删除位置在合法范围内。

然后,函数创建一个名为 begin 的迭代器,初始值为 pos 的下一个位置,即要删除的元素之后的位置

接着,使用一个循环将 begin 位置及其后面的元素逐个向前移动一个位置,覆盖掉要删除的元素。这样就相当于将删除位置的元素覆盖掉,从而实现删除操作。

最后,递减 _finish 指针,表示容器中少了一个元素,然后返回原始的删除位置的迭代器

3.4.4 赋值运算符重载

operator=

vector<T>& operator=(vector<T> v)
{
    swap(v);
    return *this;
}

这个赋值运算符重载是一个实现 C++ 中的拷贝交换技术(Copy-and-Swap Idiom)的常见写法,用于实现自定义的赋值操作。该赋值运算符接受一个传值的参数 v,这里通过传值来进行拷贝构造一个临时的 vector 对象,然后调用 swap(v) 实现了将当前对象的数据与临时对象进行交换。这样,临时对象的数据会被赋值给当前对象,而临时对象会在函数结束时被析构,从而释放掉原来当前对象的资源。

这种写法的好处在于它可以避免拷贝构造和析构造成的额外开销,从而提高了效率。同时,交换操作的实现通常在类内部对各个成员进行指针交换,因此不会涉及数据的实际拷贝。

总的来说,这个赋值运算符实现了一种高效的赋值操作,是 C++ 中常用的实现方式之一。

vector模拟实现全部代码

#pragma once
#include <assert.h>
#include <iostream>
namespace bit
{
  template<class T>
  class vector
  {
  public:
    typedef T* iterator;
    typedef const T* const_iterator;
    iterator begin()
    {
      return _start;
    }
    iterator end()
    {
      return _finish;
    }
    const_iterator begin() const
    {
      return _start;
    }
    const_iterator end() const
    {
      return _finish;
    }
    vector()
      :_start(nullptr)
      , _finish(nullptr)
      , _end_of_storage(nullptr)
    {}
    //vector(const vector<T>& v)
    //{
    //  _start = new T[v.size()]; // v.capacity()也可以
    //  //memcpy(_start, v._start, sizeof(T)*v.size());
    //  for (size_t i = 0; i < v.size(); ++i)
    //  {
    //    _start[i] = v._start[i];
    //  }
    //  _finish = _start + v.size();
    //  _end_of_storage = _start + v.size();
    //}
    /*vector(const vector<T>& v)
      :_start(nullptr)
      , _finish(nullptr)
      , _end_of_storage(nullptr)
    {
      reserve(v.size());
      for (const auto& e : v)
      {
        push_back(e);
      }
    }*/
    vector(int n, const T& val = T())
      :_start(nullptr)
      , _finish(nullptr)
      , _end_of_storage(nullptr)
    {
      reserve(n);
      for (size_t i = 0; i < n; ++i)
      {
        push_back(val);
      }
    }
    vector(size_t n, const T& val = T())
      :_start(nullptr)
      , _finish(nullptr)
      , _end_of_storage(nullptr)
    {
      reserve(n);
      for (size_t i = 0; i < n; ++i)
      {
        push_back(val);
      }
    }
    template <class InputIterator>
    vector(InputIterator first, InputIterator last)
      :_start(nullptr)
      , _finish(nullptr)
      , _end_of_storage(nullptr)
    {
      while (first != last)
      {
        push_back(*first);
        ++first;
      }
    }
    void swap(vector<T>& v)
    {
      std::swap(_start, v._start);
      std::swap(_finish, v._finish);
      std::swap(_end_of_storage, v._end_of_storage);
    }
    vector(const vector<T>& v)
      :_start(nullptr)
      , _finish(nullptr)
      , _end_of_storage(nullptr)
    {
      vector<T> tmp(v.begin(), v.end());
      swap(tmp);
    }
    // v1 = v2
    vector<T>& operator=(vector<T> v)
    {
      swap(v);
      return *this;
    }
    ~vector()
    {
      delete[] _start;
      _start = _finish = _end_of_storage = nullptr;
    }
    size_t capacity() const
    {
      return _end_of_storage - _start;
    }
    const T& operator[](size_t pos) const
    {
      assert(pos < size());
      return _start[pos];
    }
    T& operator[](size_t pos)
    {
      assert(pos < size());
      return _start[pos];
    }
    size_t size() const
    {
      return _finish - _start;
    }
    void reserve(size_t n)
    {
      if (n > capacity())
      {
        size_t sz = size();
        T* tmp = new T[n];
        if (_start)
        {
          //memcpy(tmp, _start, sizeof(T)*sz);
          for (size_t i = 0; i < sz; ++i)
          {
            tmp[i] = _start[i];
          }
          delete[] _start;
        }
        _start = tmp;
        _finish = _start + sz;
        _end_of_storage = _start + n;
      }
    }
    void resize(size_t n, const T& val = T())
    {
      if (n < size()) {
        // 缩小容器大小
        for (size_t i = n; i < size(); ++i) {
          _start[i].~T();  // 销毁元素
        }
        _finish = _start + n;
      }
      else if (n > size()) {
        if (n > capacity()) {
          // 需要重新分配内存
          T* new_start = new T[n];
          for (size_t i = 0; i < size(); ++i) {
            new (&new_start[i]) T(std::move(_start[i]));  // 移动构造元素
            _start[i].~T();  // 销毁原来的元素
          }
          delete[] _start;
          _start = new_start;
          _finish = _start + size();
          _end_of_storage = _start + n;
        }
        // 构造新添加的元素
        for (size_t i = size(); i < n; ++i) {
          new (&_start[i]) T(val);
        }
        _finish = _start + n;
      }
      // 若 n == size() 则不需要进行任何操作
    }
    void push_back(const T& x)
    {
        if (_finish == _end_of_storage)
        {
          reserve(capacity() == 0 ? 4 : capacity() * 2);
        }
        *_finish = x;
        ++_finish;
      //insert(end(), x);
    }
    void pop_back()
    {
      assert(_finish > _start);
      --_finish;
    }
    iterator insert(iterator pos, const T& x)
    {
      assert(pos >= _start);
      assert(pos <= _finish);
      if (_finish == _end_of_storage)
      {
        size_t len = pos - _start;
        reserve(capacity() == 0 ? 4 : capacity() * 2);
        pos = _start + len;
      }
      // 挪动数据
      iterator end = _finish - 1;
      while (end >= pos)
      {
        *(end + 1) = *end;
        --end;
      }
      *pos = x;
      ++_finish;
      return pos;
    }
    // stl 规定erase返回删除位置下一个位置迭代器
    iterator erase(iterator pos)
    {
      assert(pos >= _start);
      assert(pos < _finish);
      iterator begin = pos + 1;
      while (begin < _finish)
      {
        *(begin - 1) = *begin;
        ++begin;
      }
      --_finish;
      return pos;
    }
    T& front()
    {
      assert(size() > 0);
      return *_start;
    }
    T& back()
    {
      assert(size() > 0);
      return *(_finish - 1);
    }
  private:
    iterator _start;
    iterator _finish;
    iterator _end_of_storage;
  };
}

结语

有兴趣的小伙伴可以关注作者,如果觉得内容不错,请给个一键三连吧,蟹蟹你哟!!!

制作不易,如有不正之处敬请指出

感谢大家的来访,UU们的观看是我坚持下去的动力

在时间的催化剂下,让我们彼此都成为更优秀的人吧!!!


相关文章
|
4月前
|
存储 编译器 C++
【C++】vector介绍+模拟实现
【C++】vector介绍+模拟实现
|
28天前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
54 4
|
10天前
|
存储 对象存储 C++
C++ 中 std::array<int, array_size> 与 std::vector<int> 的深入对比
本文深入对比了 C++ 标准库中的 `std::array` 和 `std::vector`,从内存管理、性能、功能特性、使用场景等方面详细分析了两者的差异。`std::array` 适合固定大小的数据和高性能需求,而 `std::vector` 则提供了动态调整大小的灵活性,适用于数据量不确定或需要频繁操作的场景。选择合适的容器可以提高代码的效率和可靠性。
31 0
|
14天前
|
存储 编译器 C语言
【c++丨STL】vector模拟实现
本文深入探讨了 `vector` 的底层实现原理,并尝试模拟实现其结构及常用接口。首先介绍了 `vector` 的底层是动态顺序表,使用三个迭代器(指针)来维护数组,分别为 `start`、`finish` 和 `end_of_storage`。接着详细讲解了如何实现 `vector` 的各种构造函数、析构函数、容量接口、迭代器接口、插入和删除操作等。最后提供了完整的模拟实现代码,帮助读者更好地理解和掌握 `vector` 的实现细节。
27 0
|
2月前
|
存储 C++ 索引
【C++打怪之路Lv9】-- vector
【C++打怪之路Lv9】-- vector
26 1
|
2月前
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化2
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
77 6
|
2月前
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化1
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
93 7
|
2月前
|
编译器 C++
【C++】—— vector模拟实现
【C++】—— vector模拟实现
|
2月前
|
编译器 C语言 C++
【C++篇】解密 STL 动态之魂:全面掌握 C++ vector 的高效与优雅
【C++篇】解密 STL 动态之魂:全面掌握 C++ vector 的高效与优雅
62 3
|
2月前
|
C++
【C++】C++ STL探索:Vector使用与背后底层逻辑(三)
【C++】C++ STL探索:Vector使用与背后底层逻辑