• C++ vector类模拟实现


    目录

    一、成员变量

    二、构造函数

    1.默认构造 

     2.拷贝构造

    3.迭代器构造

    4.使用n个值构造

    5.赋值拷贝

    三、析构函数 

    四、vector重要成员函数

    1.size和capacity函数

     2.reserve函数

     3.resize函数

     4.push_back函数

    5.insert函数

    6.erase函数 

    7.重载operator[]


    一、成员变量

    STL库里面,vector的成员变量和string有一些不一样,他的成员变量是用了迭代器

    _start是数组起始位置

    _finish是数据内容结束位置的下一个

    _endofstorage是开辟的空间结束位置的下一个。

     

    那么vector的迭代器是又是什么呢?

    vector使用了模版,他可以适配各种类型,他的迭代器就是这个模板类型的指针

     因为vector和string一样,本质上就是数组,开辟的空间在内存上是连续的,因此使用指针当迭代器是在合理不过了。

    二、构造函数

    我们模仿一下STL里面的vector,没有使用适配器。

    1.默认构造 

    vector的默认构造很简单,直接写上就好,内容都可以不需要,因为我们在成员变量哪里给到了初始值,他会在初始化列表中自动调用,因此这里可以不需要写初始化列表。

    那么我们可以不可以不要下面这局代码呢?   

    答案是不可以的,因为我们后续还会写上其他的构造函数,那么编译器就不会提供默认生成的构造函数了。那这样我们普通的一个代码  vector 就会报错

    1. vector()
    2. {}

     2.拷贝构造

    拷贝构造调用了push_back函数,先开辟好空间,防止后续再扩容,后续尾插即可。

    1. vector(const vector& v)
    2. {
    3. reserve(v.capacity());
    4. for (auto& e : v)
    5. {
    6. push_back(e);
    7. }
    8. }

    3.迭代器构造

    这里使用了模板来处理,因为我们不仅仅想使用vector迭代器去构造类对象,我们还想使用其他类对象的迭代器去构造。也是利用尾插即可。

    1. template <class InputIterator>
    2. vector(InputIterator first, InputIterator last)
    3. {
    4. while (first != last)
    5. {
    6. push_back(*first);
    7. first++;
    8. }
    9. }

    4.使用n个值构造

    开辟n个空间,并全部赋值为给到的val参数。

    1. vector(int n, const T& val = T())
    2. {
    3. resize(n, val);
    4. }
    5. vector(size_t n, const T& val = T())
    6. {
    7. resize(n,val);
    8. }

     这里为什么我们要重载呢,一个写出int类型,一个写成size_t类型?

    我们先不写上面的int重载,下面这句代码,使用n个val进行拷贝,竟然报错了,为啥会这样?

    48行有问题,我们发现,明明我想调用的是58行的拷贝构造,为啥会到模板那里去?

    是因为此时所传的 10 和 1 都是int类型,而下面那个是 size_t和 int 两个类型,编译器认为你要用这个模板来初始化,因此会调用生成 InputIterator为int的函数,int类型去解引用,那可不就报错了嘛,为了让编译器认识两个整形,我们就重载了vector,使他能够知道我们的意思。

    5.赋值拷贝

    利用了很现代的写法,参数我们不传&,就会拷贝构造一个临时对象,这个临时对象刚好是我this需要的内容,我直接和你swap一下,你身上就有了我不要的内容了,同时出了作用域你会析构,我会引用返回,就完成了赋值拷贝。

    1. vector& operator=(vector v)
    2. {
    3. swap(_start,v._start);
    4. swap(_finish, v._finish);
    5. swap(_endofstorage, v._endofstorage);
    6. return *this;
    7. }

    三、析构函数 

    easy,直接delete[]  ,顺便置空即可。

    1. ~vector()
    2. {
    3. delete[] _start;
    4. _start = _finish = _endofstorage = nullptr;
    5. }

    四、vector重要成员函数

    1.size和capacity函数

    由于我们成员变量都是迭代器(实现方式为指针),因此size()的大小和capacity()都可以用迭代器相减的方式得到。

    1. size_t size() const
    2. {
    3. return _finish - _start;
    4. }
    5. size_t capacity() const
    6. {
    7. return _endofstorage - _start;
    8. }

     2.reserve函数

    reserve可以开辟空间,n比现在的空间大才开辟,比现在的空间小则不管,不会删除数据。

    如果需要开辟空间,则会先new出新的空间,把原有的数据数据拷贝到这个空间里,再删除原有的数据,同时对成员变量进行修改。

    注意我们在拷贝的时候不能使用memcpy,因为用memcpy拷贝,如果类型为自定义类型,就仅仅是浅拷贝,浅拷贝会在开辟新空间的时候进行delete,一旦delete,新空间也被delete了。

    这里我们选择了使用循环赋值,因为自定义类型会调用他的赋值拷贝,而他的赋值拷贝一般是深拷贝(只要写了的话),因此我们再扩容的时候就不会因为delete而发生错误了。

    1. void reserve(size_t n)
    2. {
    3. if (n > capacity())
    4. {
    5. size_t sz = size();
    6. T* tmp = new T[n];
    7. if (_start)
    8. {
    9. //memcpy对自定义类型是浅拷贝
    10. //memcpy(tmp, _start, sz * sizeof(T));
    11. //循环赋值,会调用自定义类型的赋值拷贝,就是深拷贝
    12. for (size_t i = 0; i < sz; i++)
    13. {
    14. tmp[i] = _start[i];
    15. }
    16. delete[] _start;
    17. }
    18. _start = tmp;
    19. _finish = _start + sz;
    20. _endofstorage = _start + n;
    21. }
    22. }

     3.resize函数

    resize会改变vector的size()。

    如果传的n要比size()小,那么就变成这个长度。

    如果n比size()大,就要先看扩不扩容,但是无论扩不扩容,我们都可以直接调用reserve函数,需要扩你就扩,不需要也没啥影响,后面在将你传过来的值,赋值给还未初始化的空间。

    注意在C++中一切类型都算对象,包括内置类型,因此我们传参给到的默认参数为T()  就像一个类的默认构造一样。 

    1. void resize(size_t n,const T& val = T())
    2. {
    3. if (n <= size())
    4. {
    5. _finish = _start + n;
    6. }
    7. else
    8. {
    9. reserve(n);
    10. for (size_t i = size(); i < n; i++)
    11. {
    12. _start[i] = val;
    13. }
    14. _finish = _start + n;
    15. }
    16. }

     4.push_back函数

    push_back函数先判断空间满了没有,满了就去扩容,空间capacity()为0就给4,不为0就给2倍。

    然后再*_finish这里赋值,_finish++即可。

    1. void push_back(const T& x)
    2. {
    3. if (size() == capacity())
    4. {
    5. size_t cp = capacity() == 0 ? 4 : capacity() * 2;
    6. reserve(cp);
    7. }
    8. *_finish = x;
    9. _finish++;
    10. }

    5.insert函数

    insert函数传的参数不是索引,而是迭代器!!!

    只要有插入,我们都得判断是否扩容,由于这里传递的是迭代器(vector中是指针),扩容有可能是异地扩容,因此地址会发生改变,我们扩容前先记录一下pos相对于_start的位置,扩容后再加上这个位置赋值给pos才对。

    后续就是挪动数据,挪动完赋值,_finish++,最后要返回pos(可以防止迭代器失效)。

    1. iterator insert(iterator pos,const T& x)
    2. {
    3. assert(pos >= _start);
    4. assert(pos <= _finish);
    5. if (size() == capacity())
    6. {
    7. size_t len = pos - _start;
    8. //扩容后_start位置可能会发生改变了,因此要记录pos的相对位置,改变pos的值
    9. size_t cp = capacity() == 0 ? 4 : capacity() * 2;
    10. reserve(cp);
    11. pos = _start+len;
    12. }
    13. iterator end = _finish - 1;
    14. while (end >= pos)
    15. {
    16. *(end + 1) = *end;
    17. end--;
    18. }
    19. *pos = x;
    20. _finish++;
    21. return pos;
    22. }

    6.erase函数 

    erase比insert还要简单一点,也是挪动数据,方向不一样,insert是从后往前数据往后挪动,erase是从当前位置往后向前挪动数据。再_finish--,最后返回pos(这也是为了防止迭代器失效)。

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

    7.重载operator[]

     分为普通版本和const版本,普通可读可写,const只能读。

    1. T& operator[](size_t pos)
    2. {
    3. assert(pos < size());
    4. return _start[pos];
    5. }
    6. //不可修改
    7. const T& operator[](size_t pos) const
    8. {
    9. assert(pos < size());
    10. return _start[pos];
    11. }

    最后附上总代码 

    vector.h

    1. #pragma once
    2. namespace kky
    3. {
    4. template<class T>
    5. class vector
    6. {
    7. public:
    8. typedef T* iterator;
    9. typedef const T* const_iterator;
    10. iterator begin()
    11. {
    12. return _start;
    13. }
    14. iterator end()
    15. {
    16. return _finish;
    17. }
    18. const_iterator begin() const
    19. {
    20. return _start;
    21. }
    22. const_iterator end() const
    23. {
    24. return _finish;
    25. }
    26. vector()
    27. {}
    28. vector(const vector& v)
    29. {
    30. reserve(v.capacity());
    31. for (auto& e : v)
    32. {
    33. push_back(e);
    34. }
    35. }
    36. template <class InputIterator>
    37. vector(InputIterator first, InputIterator last)
    38. {
    39. while (first != last)
    40. {
    41. push_back(*first);
    42. first++;
    43. }
    44. }
    45. vector(int n, const T& val = T())
    46. {
    47. resize(n, val);
    48. }
    49. //vector(size_t n, const T& val = T())
    50. //{
    51. // resize(n,val);
    52. //}
    53. vector& operator=(vector v)
    54. {
    55. swap(_start,v._start);
    56. swap(_finish, v._finish);
    57. swap(_endofstorage, v._endofstorage);
    58. return *this;
    59. }
    60. ~vector()
    61. {
    62. delete[] _start;
    63. _start = _finish = _endofstorage = nullptr;
    64. }
    65. size_t size() const
    66. {
    67. return _finish - _start;
    68. }
    69. size_t capacity() const
    70. {
    71. return _endofstorage - _start;
    72. }
    73. void reserve(size_t n)
    74. {
    75. if (n > capacity())
    76. {
    77. size_t sz = size();
    78. T* tmp = new T[n];
    79. if (_start)
    80. {
    81. //memcpy对自定义类型是浅拷贝
    82. //memcpy(tmp, _start, sz * sizeof(T));
    83. //循环赋值,会调用自定义类型的赋值拷贝,就是深拷贝
    84. for (size_t i = 0; i < sz; i++)
    85. {
    86. tmp[i] = _start[i];
    87. }
    88. delete[] _start;
    89. }
    90. _start = tmp;
    91. _finish = _start + sz;
    92. _endofstorage = _start + n;
    93. }
    94. }
    95. void resize(size_t n,const T& val = T())
    96. {
    97. if (n <= size())
    98. {
    99. _finish = _start + n;
    100. }
    101. else
    102. {
    103. reserve(n);
    104. for (size_t i = size(); i < n; i++)
    105. {
    106. _start[i] = val;
    107. }
    108. _finish = _start + n;
    109. }
    110. }
    111. void push_back(const T& x)
    112. {
    113. if (size() == capacity())
    114. {
    115. size_t cp = capacity() == 0 ? 4 : capacity() * 2;
    116. reserve(cp);
    117. }
    118. *_finish = x;
    119. _finish++;
    120. }
    121. iterator insert(iterator pos,const T& x)
    122. {
    123. assert(pos >= _start);
    124. assert(pos <= _finish);
    125. if (size() == capacity())
    126. {
    127. size_t len = pos - _start;
    128. //扩容后_start位置可能会发生改变了,因此要记录pos的相对位置,改变pos的值
    129. size_t cp = capacity() == 0 ? 4 : capacity() * 2;
    130. reserve(cp);
    131. pos = _start+len;
    132. }
    133. iterator end = _finish - 1;
    134. while (end >= pos)
    135. {
    136. *(end + 1) = *end;
    137. end--;
    138. }
    139. *pos = x;
    140. _finish++;
    141. return pos;
    142. }
    143. iterator erase(iterator pos)
    144. {
    145. assert(pos >= _start);
    146. assert(pos < _finish);
    147. iterator it = pos;
    148. while (it < _finish - 1)
    149. {
    150. *it = *(it +1);
    151. ++it;
    152. }
    153. _finish--;
    154. return pos;
    155. }
    156. T& operator[](size_t pos)
    157. {
    158. assert(pos < size());
    159. return _start[pos];
    160. }
    161. //不可修改
    162. const T& operator[](size_t pos) const
    163. {
    164. assert(pos < size());
    165. return _start[pos];
    166. }
    167. private:
    168. iterator _start = nullptr;
    169. iterator _finish = nullptr;
    170. iterator _endofstorage = nullptr;
    171. };
    172. void test01()
    173. {
    174. vector<int> v;
    175. v.push_back(1);
    176. v.push_back(2);
    177. v.push_back(3);
    178. v.push_back(4);
    179. v.push_back(5);
    180. for (size_t i = 0; i < v.size(); i++)
    181. {
    182. cout << v[i] << " ";
    183. }
    184. cout << endl;
    185. for (auto e : v)
    186. {
    187. cout << e << " ";
    188. }
    189. }
    190. void test02()
    191. {
    192. vector<int> v;
    193. v.push_back(1);
    194. v.push_back(2);
    195. v.push_back(3);
    196. v.push_back(4);
    197. v.push_back(5);
    198. v.resize(10, 6);
    199. for (auto e : v)
    200. {
    201. cout << e << " ";
    202. }
    203. cout << endl;
    204. v.insert(v.begin(), 30);
    205. for (auto e : v)
    206. {
    207. cout << e << " ";
    208. }
    209. cout << endl;
    210. }
    211. void test03()
    212. {
    213. vector<int> v;
    214. v.push_back(1);
    215. v.push_back(2);
    216. v.push_back(3);
    217. v.push_back(4);
    218. v.push_back(5);
    219. for (auto e : v)
    220. {
    221. cout << e << " ";
    222. }
    223. cout << endl;
    224. v.erase(v.begin());
    225. for (auto e : v)
    226. {
    227. cout << e << " ";
    228. }
    229. cout << endl;
    230. v.erase(v.begin()+2);
    231. for (auto e : v)
    232. {
    233. cout << e << " ";
    234. }
    235. }
    236. void test04()
    237. {
    238. vector<int> v;
    239. v.push_back(1);
    240. v.push_back(2);
    241. v.push_back(3);
    242. v.push_back(4);
    243. v.push_back(5);
    244. v.push_back(6);
    245. vector<int>::iterator it = v.begin();
    246. while (it != v.end())
    247. {
    248. if (*it % 2 == 0)
    249. {
    250. it = v.erase(it);
    251. }
    252. else
    253. {
    254. it++;
    255. }
    256. }
    257. for (auto e : v)
    258. {
    259. cout << e << " ";
    260. }
    261. }
    262. void test05()
    263. {
    264. vector<int> v;
    265. v.push_back(1);
    266. v.push_back(2);
    267. v.push_back(3);
    268. v.push_back(4);
    269. v.push_back(5);
    270. v.push_back(6);
    271. vector<int> v2(v);
    272. for (auto e : v)
    273. {
    274. cout << e << " ";
    275. }
    276. cout << endl;
    277. for (auto e : v2)
    278. {
    279. cout << e << " ";
    280. }
    281. cout << endl;
    282. vector<int> v3;
    283. v3.push_back(1);
    284. v3 = v;
    285. for (auto e : v3)
    286. {
    287. cout << e << " ";
    288. }
    289. }
    290. void test06()
    291. {
    292. vector<int> v(10, 1);
    293. for (auto e : v)
    294. {
    295. cout << e << " ";
    296. }
    297. cout << endl;
    298. std::string s("123456");
    299. vector<int> v1(s.begin(), s.end());
    300. for (auto e : v1)
    301. {
    302. cout << e << " ";
    303. }
    304. cout << endl;
    305. }
    306. void test07()
    307. {
    308. vector<int>v1(10, 1);
    309. vector<int>v2(10, 2);
    310. v1 = v2;
    311. for (auto e : v1)
    312. {
    313. cout << e << " ";
    314. }
    315. cout << endl;
    316. }
    317. }

    test.cpp

    1. #include
    2. using namespace std;
    3. #include
    4. #include"vector.h"
    5. int main()
    6. {
    7. kky::test07();
    8. }

  • 相关阅读:
    Unity笔记(10):SHOOT GAME EXAMPLE【2D】
    Spring Boot 自定义注解
    7-29 删除字符串中的子串
    C# OpenCvSharp 环形文字处理 直角坐标与极坐标转换
    c语言入门---操作符
    error while loading shared libraries: libgo.so.19 错误的解决
    如何学好次世代3D建模,学些什么,达到什么标准才能入行?
    【jmeter的使用】【性能测试1】
    动环监控系统的主要功能,动环监控系统的监控对象有哪些
    Python面向对象,实现图片处理案例,支持:高斯模糊、Canny边缘检测、反转边缘图像、生成手绘效果、调亮度......等等
  • 原文地址:https://blog.csdn.net/kkbca/article/details/133925279