当前位置: 首页 > news >正文

C++:vector的模拟实现

hello,各位小伙伴,本篇文章跟大家一起学习《C++:vector的模拟实现》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 !
如果本篇文章对你有帮助,还请各位点点赞!!!
在这里插入图片描述

话不多说,开始进入正题

文章目录

    • :maple_leaf:全代码
    • :maple_leaf:讲解
      • :leaves:一个类`vector`和一个结构体`Reverse_iterator`
      • :leaves:`vector`的迭代器
      • :leaves:`vector`的成员函数
      • :leaves:析构函数
      • :leaves:迭代器
      • :leaves:交换函数
      • :leaves:赋值重载函数
      • :leaves:`vector`相关的容器函数
      • :leaves:`reserve`函数
      • :leaves:resize函数
      • :leaves:[]重载函数
      • :leaves:尾插函数和尾删函数
      • :leaves:erase函数
      • :leaves:插入函数
    • :maple_leaf:反向迭代器对正向迭代器的复用

🍁全代码

#pragma once
#include<iostream>
#include <assert.h>
#include <stdbool.h>using namespace std;namespace My_vector
{// 适配器 -- 复用template<class Iterator, class Ref, class Ptr>struct Reverse_iterator{Iterator _it;typedef Reverse_iterator<Iterator, Ref, Ptr> Self;Reverse_iterator(Iterator it):_it(it){}Ref operator*(){Iterator tmp = _it;return *(--tmp);}Ptr operator->(){return &(operator*());}Self& operator++(){--_it;return *this;}Self& operator--(){++_it;return *this;}bool operator!=(const Self& s){return _it != s._it;}};template <class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;reverse_iterator rbegin(){return iterator(end());}reverse_iterator rend(){return iterator(begin());}const_reverse_iterator rbegin(){return const_iterator(end());}const_reverse_iterator rend(){return const_iterator(begin());}vector():_start(nullptr), _finish(nullptr), _endOfStorage(nullptr){}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endOfStorage, v._endOfStorage);}vector<T>& operator=(vector<T> v)//c = a;{					// 直接崩掉就是因为现代的赋值运算符重载是传值传参,会调用拷贝构造构造个临时变量,拷贝构造也需要初始化swap(v);return *this;}vector(const vector<T>& v):_start(nullptr), _finish(nullptr), _endOfStorage(nullptr){reserve(v.capacity());for (auto e : v){push_back(e);}}template<class InPutIterator>vector(InPutIterator first, InPutIterator last){while (first != last){push_back((*first));++first;}}vector(initializer_list<T> a){reserve(a.size());for (auto e : a){push_back(e);}}vector(size_t n, const T& val = T()){reserve(n);for (int i = 0; i < n; ++i){push_back(val);}}~vector(){if (_start){delete[] _start;_start = _finish = _endOfStorage = nullptr;}}bool empty() const{return _start == _finish;}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin()const{return _start;}const_iterator end()const{return _finish;}size_t size()const{return _finish - _start;}size_t capacity()const{return _endOfStorage - _start;}void reserve(size_t n){if (n > capacity()){size_t oldsize = size();T* tmp = new T[n];if (_start){for (size_t i = 0; i < oldsize; ++i)tmp[i] = _start[i];// 3. 释放旧空间delete[] _start;}_start = tmp;_finish = _start + oldsize;_endOfStorage = _start + n;}}void resize(size_t n, const T& value = T()){if (n <= size()){_finish = _start + n;return;}if (n > capacity()){reserve(n);}iterator lt = _finish;_finish = _start + n;while (lt != _finish){*lt = value;++lt;}}T& operator[](size_t i){assert(i < size());return _start[i];}const T& operator[](size_t i)const{assert(i < size());return _start[i];}void push_back(const T& t){/*if (_finish == _endOfStorage){size_t newcapacity = (capacity() == 0) ? 4 : 2 * capacity();reserve(newcapacity);}*_finish = t;++_finish;*/insert(end(), t);}void popback(){assert(_start != _finish);--_finish;}void erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator end = pos + 1;while (end < _finish){*(end - 1) = *end;++end;}--_finish;}iterator insert(iterator pos, const T& t){assert(pos >= _start);assert(pos <= _finish);// 空间不够先进行增容if (_finish == _endOfStorage){//size_t size = size();size_t len = pos - _start;size_t newCapacity = (0 == capacity()) ? 4 : capacity() * 2;reserve(newCapacity);// 如果发生了增容,需要重置pospos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = t;++_finish;return pos;}iterator insert(iterator pos,size_t n ,const T& t){assert(pos >= _start);assert(pos <= _finish);// 空间不够先进行增容while (_finish + n >= _endOfStorage){//size_t size = size();size_t len = pos - _start;size_t newCapacity = (0 == capacity()) ? 4 : capacity() * 2;reserve(newCapacity);// 如果发生了增容,需要重置pospos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + n) = *end;--end;}int cnt = 0;while (cnt < n){*pos = t;++pos;++cnt;}_finish += n;return pos;}private:iterator _start;		// 指向数据块的开始iterator _finish;		// 指向有效数据的尾iterator _endOfStorage;  // 指向存储容量的尾};
}

🍁讲解

🍃一个类vector和一个结构体Reverse_iterator

vector里私有成员变量有:

iterator _start;		// 指向数据块的开始
iterator _finish;		// 指向有效数据的尾
iterator _endOfStorage; // 指向所开空间的尾

结构体Reverse_iterator成员变量有:

Iterator _it;// 迭代器,因为对于反向迭代器我们可以复用正向迭代器

🍃vector的迭代器

由于迭代器类似于指针,所以我们在这里用指针代替:

// 正向迭代器
typedef T* iterator;
typedef const T* const_iterator;// 反向迭代器
typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

🍃vector的成员函数

  • 1.默认构造函数:
vector():_start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
{}
  • 2.传参构造函数

传元素个数和值(可不写,调用该类型的构造函数)
由于此原因,所以内置类型也就有了自己的默认构造函数

vector(size_t n, const T& val = T())
{reserve(n);for (int i = 0; i < n; ++i){push_back(val);// vector的尾插成员函数}
}

传迭代器区间

template<class InPutIterator>
vector(InPutIterator first, InPutIterator last)
{while (first != last){push_back((*first));++first;}
}

传初始化列表

vector(initializer_list<T> a)
{reserve(a.size());for (auto e : a){push_back(e);}
}
  • 3.拷贝构造函数
vector(const vector<T>& v):_start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
{reserve(v.capacity());for (auto e : v){push_back(e);}
}

🍃析构函数

~vector()
{if (_start){delete[] _start;_start = _finish = _endOfStorage = nullptr;}
}

🍃迭代器

// 正向迭代器
iterator begin()
{return _start;
}iterator end()
{return _finish;
}const_iterator begin()const
{return _start;
}const_iterator end()const
{return _finish;
}// 反向迭代器
reverse_iterator rbegin()
{return iterator(end());// 复用正向迭代器
}reverse_iterator rend()
{return iterator(begin());// 复用正向迭代器
}const_reverse_iterator rbegin()
{return const_iterator(end());// 复用正向迭代器
}const_reverse_iterator rend()
{return const_iterator(begin());// 复用正向迭代器
}

🍃交换函数

void swap(vector<T>& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endOfStorage, v._endOfStorage);
}

🍃赋值重载函数

vector<T>& operator=(vector<T> v)//c = a;
{swap(v);// 复用交换函数return *this;
}

🍃vector相关的容器函数

  • 判断是否为空
bool empty() const
{return _start == _finish;
}
  • 返回vrctor的大小
size_t size()const
{return _finish - _start;
}
  • 返回该vector所开的空间
size_t capacity()const
{return _endOfStorage - _start;
}

🍃reserve函数

预留空间,大大降低了数组需要被重新分配大小为了增加存储空间所用的时间,提高了效率

void reserve(size_t n)
{if (n > capacity()){size_t oldsize = size();T* tmp = new T[n];if (_start){for (size_t i = 0; i < oldsize; ++i)tmp[i] = _start[i];// 3. 释放旧空间delete[] _start;}_start = tmp;_finish = _start + oldsize;_endOfStorage = _start + n;}
}

由于重新分配空间会导致指针_start,_finish,_endOfStorage失效,所以使用了oldsize记录_start和_finish的距离。

🍃resize函数

// 扩容时可以传第二个参数value来对后面的空间初始化

void resize(size_t n, const T& value = T())
{// 缩容的情况if (n <= size()){_finish = _start + n;return;}// 扩容的情况if (n > capacity()){reserve(n);// 开空间}iterator lt = _finish;_finish = _start + n;while (lt != _finish){*lt = value;++lt;}
}

🍃[]重载函数

T& operator[](size_t i)
{assert(i < size());// 检查是否越界访问return _start[i];
}const T& operator[](size_t i)const
{assert(i < size());return _start[i];
}

🍃尾插函数和尾删函数

  • 尾插函数
void push_back(const T& t)
{if (_finish == _endOfStorage)// 判断是否需要扩容{size_t newcapacity = (capacity() == 0) ? 4 : 2 * capacity();reserve(newcapacity);}*_finish = t;++_finish;// insert(end(), t);// 复用插入函数
}
  • 尾删函数
void popback()
{assert(_start != _finish);--_finish;
}

🍃erase函数

  • 销毁函数
void erase(iterator pos)
{assert(pos >= _start);// 判断是否越界assert(pos < _finish);// 判断是否越界iterator end = pos + 1;while (end < _finish){*(end - 1) = *end;++end;}--_finish;
}

🍃插入函数

  • 插入一个元素
iterator insert(iterator pos, const T& t)
{assert(pos >= _start);assert(pos <= _finish);// 空间不够先进行增容if (_finish == _endOfStorage){//size_t size = size();size_t len = pos - _start;size_t newCapacity = (0 == capacity()) ? 4 : capacity() * 2;reserve(newCapacity);// 如果发生了增容,需要重置pos,迭代器失效问题pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = t;++_finish;return pos;
}
  • 插入多个元素
iterator insert(iterator pos, size_t n, const T& t)
{assert(pos >= _start);assert(pos <= _finish);// 空间不够先进行增容while (_finish + n >= _endOfStorage){//size_t size = size();size_t len = pos - _start;size_t newCapacity = (0 == capacity()) ? 4 : capacity() * 2;reserve(newCapacity);// 如果发生了增容,需要重置pos,迭代器失效问题pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + n) = *end;--end;}int cnt = 0;while (cnt < n){*pos = t;++pos;++cnt;}_finish += n;return pos;
}

🍁反向迭代器对正向迭代器的复用

这里3个模板参数,就是为了让编译器去判断该调用什么类型返回值的成员函数

// 适配器 -- 复用
//             迭代器           引用        指针
template<class Iterator, class Ref, class Ptr>
struct Reverse_iterator
{Iterator _it;// 成员变量,正向迭代器typedef Reverse_iterator<Iterator, Ref, Ptr> Self;// 构造函数Reverse_iterator(Iterator it):_it(it){}Ref operator*(){Iterator tmp = _it;return *(--tmp);}Ptr operator->(){return &(operator*());}Self& operator++(){--_it;return *this;}Self& operator--(){++_it;return *this;}bool operator!=(const Self& s){return _it != s._it;}
};

你学会了吗?
好啦,本章对于《C++:vector的模拟实现》的学习就先到这里,如果有什么问题,还请指教指教,希望本篇文章能够对你有所帮助,我们下一篇见!!!

如你喜欢,点点赞就是对我的支持,感谢感谢!!!

请添加图片描述

相关文章:

  • Maven 中的 classifier 属性用过没?
  • chrome 浏览器历史版本下载
  • 从openstack环境中将服务器镜像导出的简单办法
  • 分享 ASP.NET Core Web Api 中间件获取 Request Body 两个方法
  • html+CSS部分基础运用9
  • 大数据系统架构师的论文如何写
  • 【排序算法】选择排序
  • 浅谈线性化
  • 如何修改开源项目中发现的bug?
  • 使用Spring Boot自定义注解 + AOP实现基于IP的接口限流和黑白名单
  • 【Django】开发个人博客系统【1】
  • 【LeetCode】38.外观数列
  • 第P9周:YOLOv5-Backbone模块实现
  • Leetcode刷题笔记7
  • Java集合【超详细】2 -- Map、可变参数、Collections类
  • 【vuex入门系列02】mutation接收单个参数和多个参数
  • ComponentOne 2017 V2版本正式发布
  • echarts花样作死的坑
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • js学习笔记
  • Linux中的硬链接与软链接
  • Mithril.js 入门介绍
  • mysql innodb 索引使用指南
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 安装python包到指定虚拟环境
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • ​渐进式Web应用PWA的未来
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • (7)摄像机和云台
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第1节 (全局数据、栈和堆)
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (八)Flink Join 连接
  • (二) 初入MySQL 【数据库管理】
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (附源码)springboot优课在线教学系统 毕业设计 081251
  • (论文阅读11/100)Fast R-CNN
  • (十一)c52学习之旅-动态数码管
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (一)十分简易快速 自己训练样本 opencv级联haar分类器 车牌识别
  • (转)c++ std::pair 与 std::make
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • (转)JAVA中的堆栈
  • (转)shell调试方法
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .Net - 类的介绍
  • .net CHARTING图表控件下载地址
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .net oracle 连接超时_Mysql连接数据库异常汇总【必收藏】
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • .NET框架类在ASP.NET中的使用(2) ——QA
  • .NET与 java通用的3DES加密解密方法