当前位置:   article > 正文

vector底层实现及深层次拷贝问题_vector怎么拷贝

vector怎么拷贝

目录

大框架

接口实现

深层次拷贝问题(两次深拷贝)


大框架

为了与库里实现的更接近一些,先来看一下STL中是如何实现vector的(这里不是PJ版,PJ版稍微晦涩一点不容易理解,这里采用Linux下g++的版本)这里仅就大体框架做个简单介绍,其中复杂的概念不做过多解释。

 首先是vector定义的模板参数T和Alloc,这是空间配置器是一种底层实现机制,使用角度不用管。

可以看到源码做了很多typedef,主要是对格式的控制和方便理解编写。其中将T* typedef成了iterator,这个要注意,后面protected 成员变量会用到。

 这里成员变量就用到了刚刚typedef的iterator,实际上就是T* start ; T* finish;  T* end_of_storage;

T就是实例化模板参数。好像与我们设想的变量不太一样,我们设想的应该是有size和capacity的,但是这里全部统一使用指针,其实只是改变了使用方式,本质还是一样的。

 假设存在size(有效数据个数),capacity(容量),那么finish也可以表示成start+size,end_of_storage也可以表示成strat+capacity,本质是一样的。

后面是各个接口的实现,后面我们自己实现的时候具体说明,先把大框架搭建起来。

  1. namespace bc
  2. {
  3. template<class T>
  4. class vector
  5. {
  6. public:
  7. typedef T* iterator;
  8. private:
  9. iterator _start;
  10. iterator _finish;
  11. iterator _end_of_storage;
  12. };
  13. }

为了避免和库里的冲突,将我们的实现代码封在命名空间内,库里的繁杂的typedef我们省略,只保留基本的T* 的重命名和成员变量表示。

接口实现

vector.h

  1. #pragma once
  2. #include<iostream>
  3. #include<vector>
  4. #include<assert.h>
  5. using namespace std;
  6. namespace bc
  7. {
  8. template<class T>
  9. class vector
  10. {
  11. public:
  12. typedef T* iterator;
  13. vector()
  14. :_start(nullptr)
  15. , _finish(nullptr)
  16. , _end_of_storage(nullptr)
  17. { }
  18. //拷贝构造写法一
  19. //vector(const vector<T>& v)
  20. // : _start(nullptr)
  21. // , _finish(nullptr)
  22. // , _end_of_storage(nullptr)
  23. //{
  24. // reserve(size());
  25. // for (auto& e : v) {
  26. // push_back(e);
  27. // }
  28. //}
  29. //拷贝构造现代写法
  30. template<class InputIterator>
  31. vector(InputIterator first, InputIterator last)
  32. : _start(nullptr)
  33. , _finish(nullptr)
  34. , _end_of_storage(nullptr)
  35. {
  36. while (first != last) {
  37. push_back(*first);
  38. first++;
  39. }
  40. }
  41. vector(vector<T>& v)
  42. : _start(nullptr)
  43. , _finish(nullptr)
  44. , _end_of_storage(nullptr)
  45. {
  46. vector<T> tmp(v.begin(), v.end());
  47. swap(tmp);
  48. }
  49. vector(size_t n, const T& val= T())
  50. : _start(nullptr)
  51. , _finish(nullptr)
  52. , _end_of_storage(nullptr)
  53. {
  54. reserve(n);
  55. for (size_t i = 0; i < n; ++i) {
  56. push_back(val);
  57. }
  58. }
  59. //函数重载
  60. vector(int n, const T& val= T())
  61. : _start(nullptr)
  62. , _finish(nullptr)
  63. , _end_of_storage(nullptr)
  64. {
  65. reserve(n);
  66. for (int i = 0; i < n; ++i) {
  67. push_back(val);
  68. }
  69. }
  70. ~vector() {
  71. delete[]_start;
  72. _start = _finish = _end_of_storage = nullptr;
  73. }
  74. vector<T>& operator=(vector<T> v) {
  75. swap(v);
  76. return *this;
  77. }
  78. size_t size()const {
  79. return _finish - _start;
  80. }
  81. size_t capacity()const {
  82. return _end_of_storage - _start;
  83. }
  84. iterator begin() {
  85. return _start;
  86. }
  87. iterator end() {
  88. return _finish;
  89. }
  90. const iterator begin() const {
  91. return _start;
  92. }
  93. const iterator end() const {
  94. return _finish;
  95. }
  96. bool empty()const {
  97. return _finish == _start;
  98. }
  99. void clear() {
  100. _finish = _start;
  101. }
  102. void swap(vector<T>& v) {
  103. std::swap(_start, v._start);
  104. std::swap(_finish, v._finish);
  105. std::swap(_end_of_storage, v._end_of_storage);
  106. }
  107. T& operator[](size_t pos) {
  108. assert(pos < size());
  109. return _start[pos];
  110. }
  111. const T& operator[](size_t pos) const {
  112. assert(pos < size());
  113. return _start[pos];
  114. }
  115. void resize(size_t n, T val = T()) {
  116. if (n > capacity()) {
  117. reserve(n);
  118. }
  119. if (n > size() && n <= capacity()) {
  120. while (_finish < _start + n) {
  121. *_finish = val;
  122. ++_finish;
  123. }
  124. }
  125. if (n <= size()) {
  126. _finish = _start + n;
  127. }
  128. }
  129. void reserve(size_t n) {
  130. if (n > capacity()) {
  131. size_t oldsize = size();
  132. T* tmp = new T[n];
  133. if (_start != nullptr) {
  134. memcpy(tmp, _start, sizeof(T) * oldsize);
  135. /*for (size_t i = 0; i < oldsize; ++i) {
  136. tmp[i] = _start[i];
  137. }*/
  138. delete[]_start;
  139. }
  140. _start = tmp;
  141. _finish = tmp + oldsize;
  142. _end_of_storage = _start + n;
  143. }
  144. }
  145. void push_back(const T& x) {
  146. if (_finish == _end_of_storage) {
  147. size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
  148. reserve(newcapacity);
  149. }
  150. *_finish = x;
  151. ++_finish;
  152. }
  153. void pop_back() {
  154. assert(!empty());
  155. _finish--;
  156. }
  157. //迭代器失效
  158. iterator insert(iterator pos, const T& x) {
  159. assert(pos >= _start);
  160. assert(pos < _finish);
  161. if (_finish == _end_of_storage) {
  162. size_t len = pos - _start;
  163. size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
  164. reserve(newcapacity);
  165. pos = _start + len;
  166. }
  167. iterator end = _finish - 1;
  168. while (end >= pos) {
  169. *(end + 1) = *(end);
  170. --end;
  171. }
  172. *pos = x;
  173. _finish++;
  174. return pos;
  175. }
  176. iterator erase(iterator pos) {
  177. assert(pos >= _start);
  178. assert(pos < _finish);
  179. iterator begin = pos + 1;
  180. while (begin < _finish) {
  181. *(begin-1) = *(begin);
  182. ++begin;
  183. }
  184. _finish--;
  185. return pos;
  186. }
  187. private:
  188. iterator _start;
  189. iterator _finish;
  190. iterator _end_of_storage;
  191. };

下面是我给出的测试用例:

vector.h

  1. void Test1() {
  2. vector<int>a;
  3. a.push_back(1);
  4. a.push_back(1);
  5. a.push_back(1);
  6. a.push_back(1);
  7. a.push_back(1);
  8. cout << a.capacity() << endl;
  9. for (size_t i = 0; i < a.size(); ++i)
  10. {
  11. cout << a[i] << " ";
  12. }
  13. cout << endl;
  14. vector<int>::iterator it = a.begin();
  15. while (it != a.end()) {
  16. cout << (*it) << " ";
  17. it++;
  18. }
  19. cout << endl;
  20. //a.resize(2);
  21. for (auto e : a) {
  22. cout << e << " ";
  23. }
  24. cout << endl;
  25. cout << a.empty() << endl;
  26. a.pop_back();
  27. for (auto e : a) {
  28. cout << e << " ";
  29. }
  30. cout << endl;
  31. }
  32. void Test2() {
  33. vector<int> a;
  34. a.push_back(1);
  35. a.push_back(1);
  36. a.push_back(1);
  37. a.push_back(1);
  38. for (auto e : a) {
  39. cout << e << " ";
  40. }
  41. cout << endl;
  42. a.insert(a.begin(), 0);
  43. for (auto e : a) {
  44. cout << e << " ";
  45. }
  46. cout << endl;
  47. vector<int>::iterator it = find(a.begin(), a.end(), 1);
  48. if (it != a.end()) {
  49. a.insert(it, 2);
  50. }
  51. for (auto e : a) {
  52. cout << e << " ";
  53. }
  54. cout << endl;
  55. (*it)++;
  56. for (auto e : a) {
  57. cout << e << " ";
  58. }
  59. cout << endl;
  60. }
  61. void Test3() {
  62. vector<int> v;
  63. v.push_back(1);
  64. v.push_back(2);
  65. v.push_back(3);
  66. v.push_back(4);
  67. v.push_back(4);
  68. v.push_back(5);
  69. vector<int>::iterator it = v.begin();
  70. while (it != v.end()) {
  71. if ((*it) % 2 == 0) {
  72. it = v.erase(it);
  73. }
  74. else {
  75. ++it;
  76. }
  77. }
  78. for (auto e : v) {
  79. cout << e << " ";
  80. }
  81. cout << endl;
  82. }
  83. void Test4() {
  84. vector<int> v;
  85. v.push_back(1);
  86. v.push_back(1);
  87. v.push_back(1);
  88. v.push_back(1);
  89. vector<int> a(v);
  90. for (auto e : a) {
  91. cout << e << " ";
  92. }
  93. cout << endl;
  94. vector<int> b;
  95. b = a;
  96. for (auto e : b) {
  97. cout << e << " ";
  98. }
  99. cout << endl;
  100. vector<int>c(10, 1);
  101. for (auto e : c) {
  102. cout << e << " ";
  103. }
  104. cout << endl;
  105. }
  106. void Test5()
  107. {
  108. vector<vector<int>> vv;
  109. vector<int> v(4, 1);
  110. vv.push_back(v);
  111. vv.push_back(v);
  112. vv.push_back(v);
  113. vv.push_back(v);
  114. vv.push_back(v);
  115. for (size_t i = 0; i < vv.size(); ++i)
  116. {
  117. for (size_t j = 0; j < vv[i].size(); ++j)
  118. {
  119. cout << vv[i][j] << " ";
  120. }
  121. cout << endl;
  122. }
  123. cout << endl;
  124. }
  125. }

test.cpp

  1. #include"vector.h"
  2. int main()
  3. {
  4. bc::Test1();
  5. bc::Test2();
  6. bc::Test3();
  7. bc::Test4();
  8. bc::Test5();
  9. /*vector<int> v;
  10. v.push_back(1);
  11. v.push_back(2);
  12. v.push_back(3);
  13. v.push_back(4);
  14. v.push_back(5);
  15. std::vector<int>::iterator it = v.begin();
  16. while (it != v.end()) {
  17. if ((*it) % 2 == 0) {
  18. v.erase(it);
  19. }
  20. ++it;
  21. }
  22. for (auto e : v) {
  23. cout << e << " ";
  24. }
  25. cout << endl;*/
  26. return 0;
  27. }

以上是常用接口的大致实现,基本功能包含在内,还有些不太常用的接口没有实现。

深层次拷贝问题(两次深拷贝)

在测试vector<vector<int>>二维数组的时候,发现一个奇怪的现象:

当创建好vector<vector<int>> vv模型,并创建出内置数组vector<int> v (4,1)后,此时想要设定行数,也就是通过push_back插入行实现时,如果插入4个以内,没有问题,超过4个就会报错。

 

 

由此我们可以判定问题出在扩容上,具体我画图来解释。

 对于vector<vector<int>>模型要有一定理解,外部的大类型是vector<>,< >里面的类型是vector<int>,所以先从内部开始创建,vector<int> v(4,1) 构造一个{1,1,1,1}的一维数组,里面构建好了,在外面通过push_back插入,相当于插入一个一个这样的一维数组,这样就构建了二维数组,push_back多少次就相当于有多少行,里面4相当于列。

vector<int> v 数组里面的元素是int类型的,外面通过_start 指针指向v数组,指针是int* 类型的,一个指针指向一个v数组,外面还有一个_start指针指向整个vector<vector<int>>,指针类型是vector<int>*

建好二维数组后来看扩容问题,当调用reserve时,需要开辟新空间tmp,用memcpy将数据传给tmp 。                   

 而memcpy是按内存将数据拷贝给tmp的,这里的拷贝是浅拷贝,这就会导致一个问题,tmp最后也会指向_start 空间,

然后memcpy结束就是delete[]_start,delete会调用析构函数将_start空间释放,这下tmp指向的空间get不到了,tmp就是野指针了。

所以要想解决这个问题,就要解决内层浅拷贝的问题,将其改为深拷贝,这样外层tmp对象深拷贝,里层tmp数据也进行深拷贝,就不会出问题了。

解决方案:1、不用memcpy,利用operator = 重载函数将数据一个一个拷贝给tmp

  1. void reserve(size_t n)
  2. {
  3. if (n > capacity())
  4. {
  5. size_t oldSize = size();
  6. T* tmp = new T[n];
  7. if (_start)
  8. {
  9. //memcpy(tmp, _start, sizeof(T)*oldSize);
  10. for (size_t i = 0; i < oldSize; ++i)
  11. {
  12. tmp[i] = _start[i];
  13. }
  14. delete[] _start;
  15. }
  16. _start = tmp;
  17. _finish = tmp + oldSize;
  18. _endofstorage = _start + n;
  19. }
  20. }

tmp[i] = _start[i] 将_start[i] 一个一个拷贝给tmp[i],这里调用operator= 是深拷贝。

  1. vector<T>& operator=(vector<T> v)
  2. {
  3. swap(v);
  4. return *this;
  5. }

但是这种方法缺点是效率太低。在C++11 中会有更好的方式解决上述问题。

以上就是深层拷贝的内容,关于底层实现还有其他不同版本,但因为复杂度等原因我们是按Linux g++使用的库实现的,感谢浏览!

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

闽ICP备14008679号