【vector模拟实现】附加代码讲解
vector模拟实现
- 一、看源代码
- 简单实现
- 1. push_back
- capacity(容量)
- size
- reserve(扩容)
- operator[ ] (元素访问)
- 2. pop_back
- 3. itorator(迭代器)
- 4.insert & erase (头插头删)
- 5. 拷贝构造和析构函数
- default关键字(强制编译器生成)
- 其他问题
一、看源代码
- 在我们自己实现 vector 的时候,我们可以参考 vector 的源代码
- 大致功能初步了解
-
- 成员变量
-
- 核心成员函数
- 根据名字连蒙带猜,通过时间看源码细节确认
我们自定义的成员变量:
template<class T>
class vector
{
public:private:T* _a;size_t _size;size_t _capacity;
};
修改后:
namespace bit //同一个域内,就不会和编译器里面的vector弄混
{template<class T>class vector{public:typedef T* iterator;private:iterator _start;iterator _finish;iterator _end_of_storage;};
}
简单实现
前情提要:我们分离定义不分离是因为分离会出现连接问题,这个我们后面会提到
1. push_back
下面是push-back的大致框架:
void push_back(const T& x)
{//如果满了就扩容if(_finish == _end_of_storage){//扩容}
}
注意:在这里我们还要实现三个前提函数:capacity()、size()、reserve()
capacity(容量)
size_t capacity()
{return _end_of_storage - _start;
}
size
size_t size()
{return _finish - _start;
}
reserve(扩容)
void reserve(size_t n)
{//直接扩容if (n > capacity()){T* tmp = new T[n]; //开辟空间memcpy(tmp, _start, sizeof(T) * size()); //拷贝delete[] _start; //释放旧空间_start = tmp; //指向新空间}_finish = _start + size();_end_of_storage = _start + n;
}
⭐通过以上代码,我们就可以开始实现👇
void push_back(const T& x)
{//如果满了就扩容if (_finish == _end_of_storage){//如果capacity 是 0 那么就给四个空间,不是就乘二倍size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;++_finish;
}
operator[ ] (元素访问)
T& operator[](size_t i)
{assert(i < size());//断言检查越界情况return _start[i];
}
问题一:测试会发现,我们没有包iostream头文件,所以cout无法使用
- 这里就涉及到一个问题 头文件 .h 在 .cpp 文件里面会展开
所以当我们在Test.cpp里面展开vector.h时,又可以使用了
- 因为展开时他会向上查找
但但但是,又有一个问题,运行报错了
- 空指针问题,通过测试,我们可以发现的是,size算法出现问题
start 是新的 但是 finish 是旧的
当我们重新扩容之后,_start == tmp , 而_ finish还是原来的那个t
- 修改后代码如下:
void reserve(size_t n)
{//直接扩容if (n > capacity()){size_t oldsize = size();T* tmp = new T[n]; //开辟空间if (_start) {memcpy(tmp, _start, sizeof(T) * size()); //拷贝delete[] _start; //释放旧空间 }_start = tmp; //指向新空间_finish = tmp + oldsize;_end_of_storage = _start + n;}}
2. pop_back
那么这个就比较简单了,代码实现如下👇:
void pop_back()
{assert(size() > 0);--_finish
}
3. itorator(迭代器)
- 在没有迭代器的情况下时,我们是不能使用范围for的
迭代器代码实现👇
typedef T* iterator;
iterator begin()
{return _start;
}
iterator end()
{return _finish;
}
- 当然,也有const迭代器
是指迭代器指向的内容不可修改
typedef const T* const_iterator;iterator begin() const
{return _start;
}
iterator end() const
{return _finish;
}
4.insert & erase (头插头删)
void test_vector3()
{bit::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.insert(v1.begin(), 0); //头插v1.erase(v1.begin()); //头删
}
运行结果:
⭐insert的的实现
void insert(iterator pos, const T& x)
{if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;
}
注意:这里的扩容会导致迭代器失效,本质上也是一种野指针,pos指向的位置已经失效了
- 所以我们只需要将pos指向新空间对应的位置就好
修改后的insert👇
void insert(iterator pos, const T& x)
{if (_finish == _end_of_storage){size_t len = pos - _start; //加上这一句计算pos的位置size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);pos = _start + len; //重置为新pos的位置}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;
}
- 紧接而来的问题,当我们调用自己写insert时,pos会失效,使得在后面不能重新在调用pos
insert(pos,100);
erase的实现代码👇
void erase(iterator pos)
{assert(pos >= _start);assert(pos <= _finish);iterator it = pos + 1;while (it != _finish){*(it - 1) = *it;**it;}--_finish;
}
- 当我们使用erase但是也会出现失效的可能性,这也说明迭代器失效不只是野指针的问题
- 这取决于VS的编译器对于iterator,我们出了作用域时,会类似标记为 false ,此时再次调用,就会报错
5. 拷贝构造和析构函数
- 拷贝构造
问题一:如果我们不写拷贝构造的话,在VS里面默认是什么
在内置类型里面,我们完成的是值拷贝,也就是所谓的浅拷贝,这不是我们所需要的
拷贝构造函数代码如下👇
void swap(vector<T>& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);
}// v1 = v3
vector<T>& operator=(vector<T>& v)
{this->swap(v);return *this;
}
//v2(v1)
vector(const vector<T>& v)
{for (auto e : v){push_back(e);}
}//但是现在并没有写构造
- 但是在这里并没有运行,所以在这里我们需要提前了解一下关键字
default关键字(强制编译器生成)
//强制编译器生成默认的
vector() = dafault;
析构函数代码如下👇
~vector()
{if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}
}
其他问题
- 有人在编译的时候可能会出现内部编译器出错
- 因为有模板的原因,编译器报错比较混乱
- 一般都是少了分号的原因
- 可以用分段注释的方法来解决
相关文章:

【vector模拟实现】附加代码讲解
vector模拟实现 一、看源代码简单实现1. push_backcapacity(容量)sizereserve(扩容)operator[ ] (元素访问) 2. pop_back3. itorator(迭代器)4.insert & erase (头插…...

本地运行ChatTTS
TTS 是将文字转为语音的模型,最近很火的开源 TTS 项目,本地可以运行,运行环境 M2 Max,差不多每秒钟 4~~5 个字。本文将介绍如何在本地运行 ChatTTS。 下载源码 首先下载源代码 git clone https://github…...

应用解析 | 面向智能网联汽车的产教融合解决方案
背景介绍 随着科技的飞速发展,智能网联汽车已成为汽车产业的新宠,引领着未来出行的潮流。然而,行业的高速发展也带来了对高素质技术技能人才的迫切需求。为满足这一需求,推动教育链、人才链与产业链、创新链的深度融合࿰…...

华为设备动态路由OSPF(单区域+多区域)实验
动态路由OSPF的配置 OSPF分类两种情况:单区域 多区域路由 OSPF单区域路由配置 OSPF:开放最短路径优先的路由协议。属于大型动态路由协议,适用于中大型的园区网。 网络拓扑: 配置步骤: 1.完成基本配置(略&a…...

R语言探索与分析19-CPI的分析和研究
一、选题背景 CPI(居民消费价格指数)作为一个重要的宏观经济指标,扮演着评估通货膨胀和居民生活水平的关键角色。在湖北省这个经济活跃的地区,CPI的波动对于居民生活、企业经营以及政府宏观经济政策制定都具有重要的影响。因此&a…...

【C++ | 拷贝构造函数】一文了解C++的 拷贝(复制)构造函数
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 ⏰发布时间⏰:2024-06-07 2…...

【工具】Vmware17 安装mac(13.6.7)虚拟机
目录 0.简介 1.环境 2.详细步骤 2.1下载mac镜像(可以选择你所需要的) 2.2 VMware安装 1)创建新的虚拟机 2)选择【典型】,点击下一步 3)选择【安装程序光盘映像文件】,点击浏览ÿ…...
mac node版本切换 nvm install nvm ls-remote N/A问题
mac 使用nvm 切换node版本失败或者 nvm install &nvm ls-remote N/A问题 一、出现情况 输入 nvm install v16.18.0输出结果 Version 16.18.0 not found try nvm is-remote•to browse available versions.输入 nvm ls-remote输出结果 N/A二、原因分析 1. 镜像包获取…...

牛客小白月赛95
vp,为后面的比赛做准备 A.相遇 #include <iostream> #include <vector> #include <algorithm> #include <set> #include <unordered_map> #include <cstring> #include <cstdio> #include <string> #include <…...

Python实现调用并执行Linux系统命令
😎 作者介绍:我是程序员洲洲,一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 🤓 同时欢迎大家关注其他专栏,我将分享Web前后端开发、人工智能、机器学习、深…...

古字画3d立体在线数字展览馆更高效便捷
在数字时代的浪潮中,大连图书馆以崭新的面貌跃然屏幕之上——3D全景图书馆。这座承载着城市文化精髓与丰富知识资源的数字图书馆,利用前沿的三维建模技术,为我们呈现了一个全新的知识世界。 随时随地,无论您身处何地,只…...

编写程序,提示用户输入以米/秒(m/s)为单位的速度v和以米/秒的平方(m/s)为单位的加速度 a,然后显示最短跑道长度。
(物理:求出跑道长度)假设一个飞机的加速度是a而起飞速度是v,那么可以使用下 面的公式计算出飞机起飞所需的最短跑道长度: 编写程序,提示用户输入以米/秒(m/s)为单位的速度v和以米/秒的平方(m/s)为单 位的加速度 a,然后显示最短跑道长度。下面…...
k8s 对外发布(ingress)
在k8s中,service的作用体现在两个方面,对集群内部,它不断跟踪pod的变化,更新endpoint中对应pod的对象,提供了ip不断变化的pod的服务发现机制; 对集群外部,他类似负载均衡器,可以在集…...

FL Studio21.2.7最新中文破解版免费激活,音乐制作全掌握!
在数字音乐制作的海洋中,你是否曾因软件的复杂操作、高昂费用而望而却步?是否梦想拥有一款既强大又亲民的音乐制作工具,让你的创作激情不受束缚?今天,让我们一起探索FL Studio21——这款官方中文破解激活码及免费版下载…...

2 - 寻找用户推荐人(高频 SQL 50 题基础版)
2.寻找用户推荐人 考点: sql里面的不等于,不包含null -- null 用数字判断筛选不出来 select name from Customer where referee_id !2 OR referee_id IS NULL;...

高考志愿填报有哪些技巧和方法
一年一度高考季,又高考志愿填报的时侯了。高考志愿填报的时侯,需要考虑的因素比较多,有的同学觉是离家越远越好,要放飞自我,家长再也管不了我了。有的同学觉得专业比学校牌子重要,只要报个好专业࿰…...
codereview时通常需要关注哪些
在团队成员之间互相进行代码审查(codereview)时,通常可以从以下几个方面来确保代码的质量和可维护性: 代码结构和格式: 检查代码是否遵循了项目约定的编码规范和风格指南。确保代码具有良好的可读性,比如合…...
DSP28335模块配置模板系列——定时器中断配置模板
一、配置步骤: 1.使能定时器时钟 EALLOW;SysCtrlRegs.PCLKCR3.bit.CPUTIMER2ENCLK 1; // CPU Timer 2EDIS; 2.设置定时器的中断向量 EALLOW;PieVectTable.TINT2 &TIM2_IRQn;EDIS;其中TIM2_IRQn时定时器中断服务程序的名称 ,将中断服务函数的地址…...

使用 Apache Commons Exec 自动化脚本执行实现 MySQL 数据库备份
😄 19年之后由于某些原因断更了三年,23年重新扬帆起航,推出更多优质博文,希望大家多多支持~ 🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Mi…...

【中间件系列】浅析redis是否适合做消息队列
文章目录 一、简单的list消息队列1.命令示例2.伪代码示例3.方案优劣 二、Pub/Sub发布订阅1.消息丢失2.消息堆积 三、相对成熟的Stream1.redis命令介绍2.多消费者组测试3.Stream会持久化吗?4.消息堆积如何解决? 总结 用redis也是比较久了,并且…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...

海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...