当前位置:   article > 正文

C++:Vector的模拟实现

C++:Vector的模拟实现

                                                   创作不易,感谢三连 !!

一,前言 

       在学习string类的时候,我们可能会发现遍历的话下标访问特别香,比迭代器用的舒服,但是下标其实只能是支持连续的空间,他的使用是非常具有局限性的,随着STL学习的深入我们会发现其实迭代器才是大佬!!Vector虽然也支持下标访问,但是很多成员函数都是用的迭代器,所以我们要模拟实现的话迭代器十分重要,vs使用的是PJ版的STL版本,比较难懂,所以我们模拟实现统一用SGI版本去实现,所以在模拟实现之前,我们要去看看他的源码到底有哪些成员变量

       SGI下的vector有三个成员变量,通过观察其他源码可以大致推断  _start是指向起始位置,_finish是指向有效数据的下一个位置(迭代器都遵循左闭右开),end_of_storage是指向有效容量的最后一个位置。

     通过这个我们可以观察到SGI版本下的迭代器其实就是一个原生指针,value_type*类型相当于是模板T对应的指针类型,有了这些大致了解,我们就可以去模拟实现啦!!

二,vector的模拟实现

    大致框架需要有模板(类外定义)/迭代器以及迭代器的获取(public定义,要有可读可写的也要有可读不可写的)/成员变量(private定义)  并且为了不和库的vector冲突,我们需要自己搞一个命名空间

  1. namespace cyx
  2. {
  3. //模板
  4. template<class T>
  5. //迭代器(可读可写)
  6. class vector
  7. {
  8. public
  9. typedef T* iterator;
  10. iterator begin()
  11. {
  12. return _start;
  13. }
  14. iterator end()
  15. {
  16. return _finish;
  17. }
  18. //迭代器(可读不可写)
  19. typedef const T* const_iterator;
  20. const_iterator begin() const
  21. {
  22. return _start;
  23. }
  24. const_iterator end() const
  25. {
  26. return _finish;
  27. }
  28. private
  29. //成员变量
  30. iterator _start;
  31. iterator _finish;
  32. iterator _end_of_storage;
  33. }
  34. }

然后我们开始实现!! 

2.1 构造函数和析构函数

2.1.1 无参构造函数

  1. //无参构造函数
  2. vector()
  3. :_start(nullptr)
  4. ,_finish(nullptr)
  5. ,_end_of_storage(nullptr)
  6. {}

2.1.2 迭代器区间构造

  1. //传别人的迭代器进行构造
  2. template<class InputIterator>
  3. vector(InputIterator first, InputIterator last)
  4. :_start(nullptr)
  5. , _finish(nullptr)
  6. , _end_of_storage(nullptr)
  7. {
  8. //这里传的是别人的迭代器,不知道会传多少数据,不能提前扩容,只能让pushback的时候去判断
  9. while (first != last)
  10. {
  11. push_back(*first);
  12. ++first;
  13. }
  14. }

 push_back是尾插数据,具体实现后面会写。

思考:为什么迭代器也要搞个类模板呢?

        答:本质上是为了让这个函数更加灵活,可以传不同类型的迭代器来帮助我们初始化!!

比如这个地方我们传string类的迭代器

 传vector类的迭代器

 2.1.3 有参构造函数(对n个存储的类型去调用他们的构造)

  1. //有参构造函数(对n个存储的类型去调用他们的构造)
  2. vector(size_t n,const T&val=T() )
  3. :_start(nullptr)
  4. , _finish(nullptr)
  5. , _end_of_storage(nullptr)
  6. {
  7. reserve(n);//因为我们知道会进多少数据,所以可以提前开空间
  8. for (int i = 0; i < n; ++i)
  9. push_back(val);
  10. }

reserve是扩容到n,具体实现后面会写。

思考:

1.缺省值T( )是什么意思

      答:这个地方的缺省值不能给0!!因为vector可能会存储内置类型,也可能会存储自定义类型,比如vector<string>,所以如果我们没给值,缺省值就要给他的默认无参构造函数,这个默认构造函数可以使用匿名对象。

2.const T&val=T()  T()不是用一次就析构吗,为什么可以用引用

     答:T()是一个用一次就析构的匿名对象,其实本质上是因为他没有名字,用T引用val可以充当他的名字,此时用val就相当于用这个匿名对象,所以匿名对象的生命周期被延长到和val一样但是由于匿名对象是一个临时变量,所以具有常性,所以必须用const修饰的val才可以当他的别名,否则会出现权限放大!!

3.非法的间接寻址是为什么?

如下图我传(10,5),会出非法间接寻址

 但是我传(10u,5)就可以正常使用了,为什么会这样??

  答:

根据上图写出一个重载的有参构造

  1. //重载一个防止间接寻址
  2. vector(int n, const T val = T())
  3. :_start(nullptr)
  4. , _finish(nullptr)
  5. , _end_of_storage(nullptr)
  6. {
  7. reserve(n);//因为我们知道会进多少数据,所以可以提前开空间
  8. for (int i = 0; i < n; ++i)
  9. push_back(val);
  10. }

 2.1.4 拷贝构造+memcpy拷贝问题+赋值重载

 但是真的有这么顺利吗??

思考:

为什么存string类就会崩了??    这就涉及到memcpy的拷贝问题

 我们以上述问题来画图解释一下

总结:

1. memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
2. 如果拷贝的是自定义类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。
       如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是
浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。

 

所以在这个地方我们的拷贝构造不能用memcpy

  1. //拷贝构造(传统)
  2. vector(const vector<T>& v)
  3. :_start(nullptr)
  4. ,_finish(nullptr)
  5. ,_end_of_storage(nullptr)
  6. {
  7. _start = new T[v.capacity()];
  8. //memcpy(_start, v._start, sizeof(T)*v.size()); 不能用memcpy 是浅拷贝
  9. for (int i = 0; i < v.size(); ++i)
  10. _start[i] = v._start[i];//实现重载运算符
  11. _finish = _start + v.size();
  12. _end_of_storage = _start + v.capacity();
  13. }

 但是真的没有问题了吗??看看这个

 但道理来说得打印出9个1  结果呢??

 原因是什么呢,我们先看看resize函数

  1. //重载赋值=(传统)
  2. vector<T>& operator=(const vector<T> &v)
  3. {
  4. T* temp = new T [v.capacity()];
  5. for(int i=0;i<v.size();++i)
  6. temp[i] = v[i];
  7. delete[]_start;
  8. _start = temp;
  9. _finish = _start +v.size();
  10. _end_of_storage = _start +v.capacity();
  11. return *this;
  12. }

 2.1.5 拷贝构造和赋值重载的现代写法

先写个swap函数

  1. //交换
  2. void swap(vector<T>& v)
  3. {
  4. std::swap(_start, v._start);
  5. std::swap(_finish, v._finish);
  6. std::swap(_end_of_storage, v._end_of_storage);
  7. }

        拷贝构造的现代写法思路:创建一个临时对象利用被拷贝对象的迭代器区间构造,然后再swap一下就可以了!

  1. vector(const vector<T>& v)
  2. :_start(nullptr)
  3. , _finish(nullptr)
  4. , _end_of_storage(nullptr)
  5. {
  6. vector<T> temp(v.begin(), v.end());//让临时对象借助迭代器区间构造出来
  7. swap(temp);//窃取革命成果
  8. }

       赋值重载的现代写法的思路:反正我自己的空间也不要了,被赋值对象传值过来(这样被赋值对象不会被修改),然后直接和临时对象swap就可以了!!

  1. vector<T>& operator=(vector<T> v)
  2. {
  3. swap(v);//反正我原来的空间也要销毁,我跟你传值过来的v直接交换,而且不会改变你
  4. return *this;
  5. }

2.1.6 析构函数 

  1. ~vector()
  2. {
  3. /*if (_start)*///delete 会自动检查空指针 没必要
  4. delete[] _start;
  5. _start = _finish = _end_of_storage = nullptr;
  6. }

注意:delete空指针是没关系的,delete会自己判断     delete出问题一般都是野指针

2.1.7 构造函数相关的全部代码

 我们发现大部分都设计要到初始化为nullptr,c11后是支持直接在成员变量那边给缺省值的,所以们可以美化一下

全部代码

  1. //无参构造函数
  2. vector()
  3. {}
  4. //有参构造函数(对n个存储的类型去调用他们的构造)
  5. vector(size_t n, const T& val = T())
  6. {
  7. reserve(n);//因为我们知道会进多少数据,所以可以提前开空间
  8. for (int i = 0; i < n; ++i)
  9. push_back(val);
  10. }
  11. //重载一个防止间接寻址
  12. vector(int n, const T val = T())
  13. {
  14. reserve(n);//因为我们知道会进多少数据,所以可以提前开空间
  15. for (int i = 0; i < n; ++i)
  16. push_back(val);
  17. }
  18. //传别人的迭代器区间进行构造
  19. template<class InputIterator>
  20. vector(InputIterator first, InputIterator last)
  21. {
  22. //这里传的是别人的迭代器,不知道会传多少数据,不能提前扩容,只能让pushback的时候去判断
  23. while (first != last)
  24. {
  25. push_back(*first);
  26. ++first;
  27. }
  28. }
  29. //拷贝构造(传统写法)
  30. vector(const vector<T>& v)
  31. {
  32. _start = new T[v.capacity()];
  33. //memcpy(_start, v._start, sizeof(T)*v.size()); 不能用memcpy 是浅拷贝
  34. for (size_t i = 0; i < v.size(); ++i)
  35. _start[i] = v._start[i];//实现重载运算符
  36. _finish = _start + v.size();
  37. _end_of_storage = _start + v.capacity();
  38. }
  39. //拷贝构造(现代写法)
  40. //vector(const vector<T>& v)
  41. //{
  42. // vector<T> temp(v.begin(), v.end());//让临时对象借助迭代器区间构造出来
  43. // swap(temp);//窃取革命成果
  44. //}
  45. //交换
  46. void swap(vector<T>& v)
  47. {
  48. std::swap(_start, v._start);
  49. std::swap(_finish, v._finish);
  50. std::swap(_end_of_storage, v._end_of_storage);
  51. }
  52. 重载赋值=(传统)
  53. vector<T>& operator=(const vector<T>& v)
  54. {
  55. T* temp = new T[v.capacity()];
  56. for (int i = 0; i < v.size(); ++i)
  57. temp[i] = v[i];
  58. delete[]_start;
  59. _start = temp;
  60. _finish = _start + v.size();
  61. _end_of_storage = _start + v.capacity();
  62. return *this;
  63. }
  64. //赋值重载现代写法
  65. //vector<T>& operator=(vector<T> v)
  66. //{
  67. // swap(v);//反正我原来的空间也要销毁,我跟你传值过来的v直接交换,而且不会改变你
  68. // return *this;
  69. //}
  70. //析构函数
  71. ~vector()
  72. {
  73. /*if (_start)*///delete 会自动检查空指针 没必要检查
  74. delete[] _start;
  75. _start = _finish = _end_of_storage = nullptr;
  76. }

 2.2 常见接口

2.2.1 获取size和capacity

  1. //获取size
  2. size_t size() const
  3. {
  4. return _finish - _start;
  5. }
  6. //获取capacoty
  7. size_t capacity() const
  8. {
  9. return _end_of_storage - _start;
  10. }

 2.2.2 判空

  1. //判空
  2. bool empty() const
  3. {
  4. return _start == _finish;
  5. }

2.2.3 重载[ ]

1.可读可写[ ]

  1. //重载[](可读可写)
  2. T& operator[](size_t pos)
  3. {
  4. assert(pos < size());
  5. return _start[pos];
  6. }

2.可读不可写[]

  1. //重载[](可读不可写)
  2. const T& operator[](size_t pos) const
  3. {
  4. assert(pos < size());
  5. return _start[pos];
  6. }

3.三种访问方法

下标

  1. //下标遍历
  2. for (int i = 0; i < v1.size(); ++i)
  3. cout << v1[i] << " ";
  4. cout << endl;

迭代器

  1. //迭代器遍历
  2. vector<int>::const_iterator it = v1.begin();
  3. while (it != v1.end())
  4. {
  5. cout << *it << " ";
  6. ++it;
  7. }
  8. cout << endl;

范围for 

  1. //范围for遍历
  2. for (auto e : v1)
  3. cout << e << " ";
  4. cout << endl;
  5. v1.resize(100);
  6. cout << v1.size() << endl;
  7. for (auto e : v1)
  8. cout << e << " ";
  9. cout << endl;

 2.2.4 提前扩容

  1. void reserve(size_t n)
  2. {
  3. size_t sz = size();//防止丢失
  4. if (n > capacity())
  5. {
  6. T* temp = new T[n];
  7. if (_start)//如果为空,就不需要拷贝也不需要释放
  8. {
  9. for (size_t i = 0; i < sz; ++i)
  10. temp[i] = _start[i];
  11. delete[] _start;
  12. }
  13. _start = temp;
  14. _finish = _start + sz;
  15. _end_of_storage = _start + n;
  16. }
  17. }

 考虑到之前的memcpy拷贝问题,这里不能用memcpy了!!

还要注意的是要提前记录size(),否则原空间销毁了就找不到了。

2.2.5 提前扩容+初始化

有三种情况,第一种是给的n比原来的size小,第二种是n比size大但是比capacity小,第三种是n比capacity大,这个时候需要扩容

  1. //提前扩容+初始化
  2. void resize(size_t n, T val = T())
  3. {
  4. //给小
  5. if (n < size())
  6. _finish = _start + n;
  7. //给大
  8. else
  9. {
  10. //容量不够就扩
  11. if (n > capacity())
  12. reserve(n);
  13. while (_finish != _start + n)
  14. {
  15. *_finish = val;
  16. ++_finish;
  17. }
  18. }
  19. }

2.2.6 尾插和尾删

  1. void push_back(const T& val)
  2. {
  3. if (_finish == _end_of_storage)
  4. reserve(capacity() == 0 ? 4 : 2 * capacity());
  5. *_finish = val;
  6. ++_finish;
  7. }
  8. //尾删
  9. void pop_back()
  10. {
  11. //防止没有元素可删
  12. assert(!empty());
  13. --_finish;
  14. }

 尾插要注意扩容之前要判断一下,因为如果是0的话怎么扩都是0

我们会发现这次的指定位置插入删除不像string那样用size_t pos 而是iterator pos

2.2.7 指定位置插入

 这样写有什么问题吗??

看似好像没有什么问题,但是如果把pushback(5)去掉

 为什么会这样呢?

原因就是扩容后空间变了,但是pos还是指向原来的空间!!

所以我们解决方案就是pos在扩容的时候要更新一下

  1. iterator insert(iterator pos, const T& val)
  2. {
  3. assert(pos >= _start);
  4. assert(pos <= _finish);
  5. if (_finish == _end_of_storage)
  6. {
  7. size_t len = pos - _start;//记录相对距离,方便更新pos
  8. reserve(capacity() == 0 ? 4 : 2 * capacity());
  9. pos = _start + len;
  10. }
  11. iterator end = _finish - 1;
  12. while (end >= pos)
  13. {
  14. *(end + 1) = *end;
  15. --end;
  16. }
  17. *pos = val;
  18. ++_finish;
  19. return pos;
  20. }

2.2.8 指定位置删除

返回值是pos的下一个位置 

  1. iterator erase(iterator pos)
  2. {
  3. assert(pos >= _start);
  4. assert(pos < _finish);
  5. iterator start = pos + 1;
  6. while (start != _finish)
  7. {
  8. *(start - 1) = *start;
  9. ++start;
  10. }
  11. --_finish;
  12. return pos;
  13. }

2.3 迭代器失效问题

会引起其底层空间改变的操作,都有可能使得迭代器失效。

 比如:resize、reserve、insert、erase、 push_back等。

2.3.1.insert的失效

就是因为扩容导致pos失效,我们需要去及时更新pos

      但是我们传的pos是值传递,所以我们更新的后pos更新,我们在后面解引用pos就会出现经典的解引用野指针问题。

 那我们怎么传回pos呢??就得用返回值!!这也是为什么insert的返回值用iterator的原因,我们想继续用的话就得去接收一下返回值,就可以了

     虽然有了返回值,我们可以去接收更新后的pos,但是一旦我们使用了任意一个可能扩容的函数,都会到时pos的失效,从而有可能回引发野指针问题,这个问题是不太好避免的,所以我们认为迭代器只能用一次,因为结果不可预测!

2.3.2 erase的失效

        erase 删除 pos 位置元素后,pos 位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果 pos 刚好是最后一个元素,删完之后 pos 刚好是 end 的位置,而 end 位置是没有元素的,那么 pos 就失效了。因此删除 vector 中任意位置上元素时,vs 就认为该位置迭代器失效了。

vs和g++对比

 结果是未定义的!!不同编译器场景可能不同,严格来说vs更严谨 

思考:

假设没有强制检查(比如我们自己写的vector),想删除删除 vector 中所有偶数

 但是如果只有4个

为什么会这样呢,我们画图分析

   从这边我们也能看到为什么erase返回值也要用iterator的原因,我们想继续用的话就得去接收一下返回值

2.3.3 扩容导致的失效

可能本来还能用,但是中间扩容过,所以也不能用了

用pos前用一样reserve,也会失效

总而言之:尽量不要复用pos迭代器,因为任何一个可能扩容的操作都会导致失效

2.4 比较不常用的接口

2.4.1 清理元素

  1. void clear() const
  2. {
  3. _finish = _start;
  4. }

2.4.2 缩容

  1. void shrink_to_fit()
  2. {
  3. size_t sz = size();//记录
  4. T* temp = new T[sz];
  5. for (size_t i = 0; i < sz; ++i)
  6. temp[i] = _start[i];
  7. delete _start;
  8. _start = temp;
  9. _finish = _start + sz;
  10. _end_of_storage = _start + sz;
  11. }

2.5 反向迭代器 

这里博主直接上代码,等list模拟实现的时候再放在一起分析

1、利用正向迭代器去封装反向迭代器

  1. //反向迭代器的封装
  2. template<class iterator, class Ref>
  3. struct ReverseIterator
  4. {
  5. typedef ReverseIterator<iterator, Ref> Self;//Ref单纯是为了控制解引用的时候是否可以被写
  6. //利用反向迭代器的类来封装正向迭代器,同时在类里面设置反向迭代器的行为
  7. ReverseIterator(iterator it)
  8. :_cur(it)
  9. {}
  10. Ref operator*()
  11. {
  12. iterator temp = _cur;
  13. --temp;
  14. return *temp;
  15. }
  16. Self& operator++()
  17. {
  18. --_cur;
  19. return *this;
  20. }
  21. Self operator++(int)
  22. {
  23. iterator temp = _cur;
  24. --_cur;
  25. return temp;
  26. }
  27. Self& operator--()
  28. {
  29. ++_cur;
  30. return *this;
  31. }
  32. Self operator--(int)
  33. {
  34. iterator temp = _cur;
  35. ++_cur;
  36. return temp;
  37. }
  38. Self operator+(int n)
  39. {
  40. iterator temp = _cur;
  41. temp-=n;
  42. return temp;
  43. }
  44. Self operator-(int n)
  45. {
  46. iterator temp = _cur;
  47. temp+= n;
  48. return temp;
  49. }
  50. bool operator!=(const Self& s)
  51. {
  52. return _cur != s._cur;
  53. }
  54. bool operator==(const Self& s)
  55. {
  56. return _cur == s._cur;
  57. }
  58. //成员变量
  59. iterator _cur;
  60. };

2、rebegin和rend

  1. //反向迭代器(可读可写)
  2. reverse_iterator rbegin()
  3. {
  4. return reverse_iterator(end());
  5. }
  6. reverse_iterator rend()
  7. {
  8. return reverse_iterator(begin());
  9. }
  10. //反向迭代器(可读不可写)
  11. const_reverse_iterator rbegin() const
  12. {
  13. return const_reverse_iterator(end());
  14. }
  15. const_reverse_iterator rend() const
  16. {
  17. return const_reverse_iterator(begin());
  18. }

三,vector实现的全部代码

  1. using namespace std;
  2. namespace cyx
  3. {
  4. //反向迭代器的封装
  5. template<class iterator, class Ref>
  6. struct ReverseIterator
  7. {
  8. typedef ReverseIterator<iterator, Ref> Self;//Ref单纯是为了控制解引用的时候是否可以被写
  9. //利用反向迭代器的类来封装正向迭代器,同时在类里面设置反向迭代器的行为
  10. ReverseIterator(iterator it)
  11. :_cur(it)
  12. {}
  13. Ref operator*()
  14. {
  15. iterator temp = _cur;
  16. --temp;
  17. return *temp;
  18. }
  19. Self& operator++()
  20. {
  21. --_cur;
  22. return *this;
  23. }
  24. Self operator++(int)
  25. {
  26. iterator temp = _cur;
  27. --_cur;
  28. return temp;
  29. }
  30. Self& operator--()
  31. {
  32. ++_cur;
  33. return *this;
  34. }
  35. Self operator--(int)
  36. {
  37. iterator temp = _cur;
  38. ++_cur;
  39. return temp;
  40. }
  41. Self operator+(int n)
  42. {
  43. iterator temp = _cur;
  44. temp-=n;
  45. return temp;
  46. }
  47. Self operator-(int n)
  48. {
  49. iterator temp = _cur;
  50. temp+= n;
  51. return temp;
  52. }
  53. bool operator!=(const Self& s)
  54. {
  55. return _cur != s._cur;
  56. }
  57. bool operator==(const Self& s)
  58. {
  59. return _cur == s._cur;
  60. }
  61. //成员变量
  62. iterator _cur;
  63. };
  64. template<class T>
  65. class vector
  66. {
  67. public:
  68. //正向迭代器
  69. typedef T* iterator;
  70. typedef const T* const_iterator;
  71. //反向迭代器
  72. typedef ReverseIterator<iterator, T&> reverse_iterator;
  73. typedef ReverseIterator<iterator, const T&> const_reverse_iterator;
  74. //正向迭代器(可读可写)
  75. iterator begin()
  76. {
  77. return _start;
  78. }
  79. iterator end()
  80. {
  81. return _finish;
  82. }
  83. //正向迭代器(可读不可写)
  84. iterator begin() const
  85. {
  86. return _start;
  87. }
  88. iterator end() const
  89. {
  90. return _finish;
  91. }
  92. //反向迭代器(可读可写)
  93. reverse_iterator rbegin()
  94. {
  95. return reverse_iterator(end());
  96. }
  97. reverse_iterator rend()
  98. {
  99. return reverse_iterator(begin());
  100. }
  101. //反向迭代器(可读不可写)
  102. const_reverse_iterator rbegin() const
  103. {
  104. return const_reverse_iterator(end());
  105. }
  106. const_reverse_iterator rend() const
  107. {
  108. return const_reverse_iterator(begin());
  109. }
  110. //无参构造函数
  111. vector()
  112. {}
  113. //有参构造函数(对n个存储的类型去调用他们的构造)
  114. vector(size_t n, const T& val = T())
  115. {
  116. reserve(n);//因为我们知道会进多少数据,所以可以提前开空间
  117. for (int i = 0; i < n; ++i)
  118. push_back(val);
  119. }
  120. //重载一个防止间接寻址
  121. vector(int n, const T val = T())
  122. {
  123. reserve(n);//因为我们知道会进多少数据,所以可以提前开空间
  124. for (int i = 0; i < n; ++i)
  125. push_back(val);
  126. }
  127. //传别人的迭代器进行构造
  128. template<class InputIterator>
  129. vector(InputIterator first, InputIterator last)
  130. {
  131. //这里传的是别人的迭代器,不知道会传多少数据,不能提前扩容,只能让pushback的时候去判断
  132. while (first != last)
  133. {
  134. push_back(*first);
  135. ++first;
  136. }
  137. }
  138. //拷贝构造(传统写法)
  139. vector(const vector<T>& v)
  140. {
  141. _start = new T[v.capacity()];
  142. //memcpy(_start, v._start, sizeof(T)*v.size()); 不能用memcpy 是浅拷贝
  143. for (size_t i = 0; i < v.size(); ++i)
  144. _start[i] = v._start[i];//实现重载运算符 完成深拷贝
  145. _finish = _start + v.size();
  146. _end_of_storage = _start + v.capacity();
  147. }
  148. //拷贝构造(现代写法)
  149. //vector(const vector<T>& v)
  150. //{
  151. // vector<T> temp(v.begin(), v.end());//让临时对象借助迭代器区间构造出来
  152. // swap(temp);//窃取革命成果
  153. //}
  154. //交换
  155. void swap(vector<T>& v)
  156. {
  157. std::swap(_start, v._start);
  158. std::swap(_finish, v._finish);
  159. std::swap(_end_of_storage, v._end_of_storage);
  160. }
  161. //重载赋值=(传统)
  162. vector<T>& operator=(const vector<T>& v)
  163. {
  164. T* temp = new T[v.capacity()];
  165. for (int i = 0; i < v.size(); ++i)
  166. temp[i] = v[i];
  167. delete[]_start;
  168. _start = temp;
  169. _finish = _start + v.size();
  170. _end_of_storage = _start + v.capacity();
  171. return *this;
  172. }
  173. //赋值重载现代写法
  174. //vector<T>& operator=(vector<T> v)
  175. //{
  176. // swap(v);//反正我原来的空间也要销毁,我跟你传值过来的v直接交换,而且不会改变你
  177. // return *this;
  178. //}
  179. //析构函数
  180. ~vector()
  181. {
  182. /*if (_start)*///delete 会自动检查空指针
  183. delete[] _start;
  184. _start = _finish = _end_of_storage = nullptr;
  185. }
  186. //获取size
  187. size_t size() const
  188. {
  189. return _finish - _start;
  190. }
  191. //获取capacoty
  192. size_t capacity() const
  193. {
  194. return _end_of_storage - _start;
  195. }
  196. //判空
  197. bool empty() const
  198. {
  199. return _start == _finish;
  200. }
  201. //重载[](可读可写)
  202. T& operator[](size_t pos)
  203. {
  204. assert(pos < size());
  205. return _start[pos];
  206. }
  207. //重载[](可读不可写)
  208. const T& operator[](size_t pos) const
  209. {
  210. assert(pos < size());
  211. return _start[pos];
  212. }
  213. //提前扩容+初始化
  214. void resize(size_t n, T val = T())
  215. {
  216. //给小
  217. if (n < size())
  218. _finish = _start + n;
  219. //给大
  220. else
  221. {
  222. //容量不够就扩
  223. if (n > capacity())
  224. reserve(n);
  225. while (_finish != _start + n)
  226. {
  227. *_finish = val;
  228. ++_finish;
  229. }
  230. }
  231. }
  232. //提前扩容
  233. void reserve(size_t n)
  234. {
  235. size_t sz = size();//防止丢失
  236. if (n > capacity())
  237. {
  238. T* temp = new T[n];
  239. if (_start)//如果为空,就不需要拷贝也不需要释放
  240. {
  241. for (size_t i = 0; i < sz; ++i)
  242. temp[i] = _start[i];
  243. delete[] _start;
  244. }
  245. _start = temp;
  246. _finish = _start + sz;
  247. _end_of_storage = _start + n;
  248. }
  249. }
  250. //尾插
  251. void push_back(const T& val)
  252. {
  253. if (_finish == _end_of_storage)
  254. reserve(capacity() == 0 ? 4 : 2 * capacity());
  255. *_finish = val;
  256. ++_finish;
  257. }
  258. //尾删
  259. void pop_back()
  260. {
  261. //防止没有元素可删
  262. assert(!empty());
  263. --_finish;
  264. }
  265. //指定位置插入
  266. iterator insert(iterator pos, const T& val)
  267. {
  268. assert(pos >= _start);
  269. assert(pos <= _finish);
  270. if (_finish == _end_of_storage)
  271. {
  272. size_t len = pos - _start;
  273. reserve(capacity() == 0 ? 4 : 2 * capacity());
  274. pos = _start + len;
  275. }
  276. iterator end = _finish - 1;
  277. while (end >= pos)
  278. {
  279. *(end + 1) = *end;
  280. --end;
  281. }
  282. *pos = val;
  283. ++_finish;
  284. return pos;
  285. }
  286. //指定位置删除
  287. iterator erase(iterator pos)
  288. {
  289. assert(pos >= _start);
  290. assert(pos < _finish);
  291. iterator start = pos + 1;
  292. while (start != _finish)
  293. {
  294. *(start - 1) = *start;
  295. ++start;
  296. }
  297. --_finish;
  298. return pos;
  299. }
  300. //清理元素
  301. void clear() const
  302. {
  303. _finish = _start;
  304. }
  305. //缩容
  306. void shrink_to_fit()
  307. {
  308. size_t sz = size();//记录
  309. T* temp = new T[sz];
  310. for (size_t i = 0; i < sz; ++i)
  311. temp[i] = _start[i];
  312. delete _start;
  313. _start = temp;
  314. _finish = _start + sz;
  315. _end_of_storage = _start + sz;
  316. }
  317. private:
  318. iterator _start= nullptr;
  319. iterator _finish= nullptr;
  320. iterator _end_of_storage= nullptr;
  321. };

有什么不懂得可以问博主哦!后面有时间再来细化接口

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/207509
推荐阅读
相关标签
  

闽ICP备14008679号