首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

C++入门小馆: 探寻vector类

  • 25-04-25 13:41
  • 4802
  • 5346
blog.csdn.net

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let's go!

我的博客:yuanManGan

我的专栏:C++入门小馆 C言雅韵集 数据结构漫游记  闲言碎语小记坊 题山采玉 领略算法真谛

目录

vector的使用:

模拟实现vector:


先来了解一下vector的使用

vector的使用:

初始化方式:

 

这一坨实现的是内存池,如果你对STL里面的内存池不满意可以自己传入内存池,自己写一个。

第一个是无参构造

第二个是构造n个一样的类型一样的值

第三个是利用迭代器区间构造。

第四个是拷贝构造。

也可以使用initializer_list类型来构造。

由于vector没有重载>>和<<运算符,但也没有必要重载,我们打印也可以用范围for来遍历。

  1. for(auto& x : v1)
  2. {
  3. cout << x << " ";
  4. }

结果: 

 

 

 这些迭代器也很眼熟了,没有什么好讲的,用法也差不多。

shrink_to_fit是用来缩容的,一般不咋用。

front和back是返回第一个和最后一个元素,可以使用下标加方括号就可以访问到所有元素了。这两个也不咋常用。

这些也是看的很眼熟了,这里在C++11有一个emplace这个和插入的功能所实现的效果是一样的,但这个使用起来更高效。

外部有一个swap和内部也有一个swap,还是类似于string类,外部的swap实现起来,造成了很多浪费。

注意这里的insert和erase要传入迭代器了,不像string能传入位置,要传入迭代器。

模拟实现vector:

我们先来看看STL源码里面的vector怎么实现的

vector要使用模版,另一个是内存池。

这是成员变量:

从下面可以看到vector的迭代器在这个版本的STL中是用原生指针来实现的,但不能说只能用原生指针来实现,其他版本可能使用其他方式实现。

_start 来指向第一个元素,_finish指向的是最后一个元素后面一个位置,_end_of_storage指向内存最大值的下一个位置。

c

 从这些就可以看出来。

好了看了基本的内容,我们就来自己实现一下吧!因为内存池这里,我还没有学习过,就先不实现了。

写个成员变量:

  1. namespace refrain
  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. }

默认构造

无参构造

  1. vector()
  2. :_start(nullptr)
  3. ,_finish(nullptr)
  4. ,_end_of_storage(nullptr)
  5. {}

容量,数量:

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

我们先来实现插入,方便我们好检查我们是否写错了

但我们实现push_back()之前要先实现一下扩容逻辑,因为push_back可以复用reserve函数。

reserve:

  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. for (int i = 0; i <= size(); i++)
  10. {
  11. tmp[i] = _start[i];
  12. }
  13. delete[] _start;
  14. }
  15. _start = tmp;
  16. _finish = _start + oldsize;
  17. _end_of_storage = _start + n;
  18. }
  19. }

注意这里这里要先用oldsize存一下原来的size不然,后面_start+size()会调用size函数

这个时候_start已经改变了,得到的finish就不是我们期望的值。

然后push_back的逻辑就简单了:

  1. void push_back(const T& x)
  2. {
  3. //检查是否需要扩容
  4. if (_finish == _end_of_storage)
  5. {
  6. size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
  7. reserve(newcapacity);
  8. }
  9. *(_finish) = x;
  10. _finish++;
  11. }

 pop_back就更简单了:

  1. void pop_back()
  2. {
  3. assert(_finish > _start);
  4. _finish--;
  5. }

我们再重载一下方括号和迭代器相关的接口,来实现打印一下。

  1. typedef T* iterator;
  2. typedef const T* const_iterator;
  3. iterator begin()
  4. {
  5. return _start;
  6. }
  7. iterator end()
  8. {
  9. return _finish;
  10. }
  11. const_iterator begin() const
  12. {
  13. return _start;
  14. }
  15. const_iterator end() const
  16. {
  17. return _finish;
  18. }
  1. T& operator[](size_t i)
  2. {
  3. return *(_start + i);
  4. }

 接下来的实现insert和erase操作的逻辑就和string差不多了

  1. void insert(iterator pos, T x)
  2. {
  3. assert(pos >= _start);
  4. assert(pos < _finish);
  5. if (_finish == _end_of_storage)
  6. {
  7. size_t len = pos - _start;
  8. size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
  9. reserve(newcapacity);
  10. pos = _start + len;
  11. }
  12. iterator it = _finish - 1;
  13. while (it >= pos)
  14. {
  15. *(it + 1) = *it;
  16. it--;
  17. }
  18. *(pos) = x;
  19. _finish++;
  20. }
  21. void erase(iterator pos)
  22. {
  23. assert(pos >= _start);
  24. assert(pos < _finish);
  25. iterator it = pos;
  26. while (it < _finish)
  27. {
  28. *(it) = *(it + 1);
  29. it++;
  30. }
  31. _finish--;
  32. }

 写下面这个方便打印

  1. void print(const vector<int>& v)
  2. {
  3. for (auto& k : v)
  4. {
  5. cout << k << " ";
  6. }
  7. cout << endl;
  8. }

我们看看下面这个程序:

我们再来写一个程序,用来删去v里面的偶数。

我们不能使用已经失效的迭代器,我们咋解决这个问题呢我们看看库里面的insert和erase

 

 它们都是有返回值的,返回指向下一个位置的迭代器。

所以我们的insert和erase就成了:

  1. iterator insert(iterator pos, T x)
  2. {
  3. assert(pos >= _start);
  4. assert(pos < _finish);
  5. if (_finish == _end_of_storage)
  6. {
  7. size_t len = pos - _start;
  8. size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
  9. reserve(newcapacity);
  10. pos = _start + len;
  11. }
  12. iterator it = _finish - 1;
  13. while (it >= pos)
  14. {
  15. *(it + 1) = *it;
  16. it--;
  17. }
  18. *(pos) = x;
  19. _finish++;
  20. return pos;
  21. }
  22. iterator erase(iterator pos)
  23. {
  24. assert(pos >= _start);
  25. assert(pos < _finish);
  26. iterator it = pos;
  27. while (it < _finish)
  28. {
  29. *(it) = *(it + 1);
  30. it++;
  31. }
  32. _finish--;
  33. return pos;
  34. }

就欧克了。这里就出现了迭代器失效的问题。

最后来实现一下赋值运算符和拷贝构造吧!

  1. vector(const vector& v)
  2. {
  3. reserve(v.capacity());
  4. for (auto& x : v)
  5. {
  6. push_back(x);
  7. }
  8. }
  9. void swap(const vector& v)
  10. {
  11. std::swap(_start, v._start);
  12. std::swap(_finish, v._finish);
  13. std::swap(_end_of_storage, v._end_of_storage);
  14. }
  15. vector& operator=(vector v)
  16. {
  17. swap(v);
  18. return *this;
  19. }

不多说了和string差不多。

注:本文转载自blog.csdn.net的yuanManGan的文章"https://blog.csdn.net/yuanManGan/article/details/147424391"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top