【vector模拟实现】附加代码讲解

vector模拟实现

  • 一、看源代码
  • 简单实现
    • 1. push_back
      • capacity(容量)
      • size
      • reserve(扩容)
      • operator[ ] (元素访问)
    • 2. pop_back
    • 3. itorator(迭代器)
    • 4.insert & erase (头插头删)
    • 5. 拷贝构造和析构函数
      • default关键字(强制编译器生成)
    • 其他问题

一、看源代码

  • 在我们自己实现 vector 的时候,我们可以参考 vector 的源代码

在这里插入图片描述

  • 大致功能初步了解
    1. 成员变量
    1. 核心成员函数
  • 根据名字连蒙带猜,通过时间看源码细节确认

我们自定义的成员变量:

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;}
}

其他问题

  • 有人在编译的时候可能会出现内部编译器出错
  • 因为有模板的原因,编译器报错比较混乱
  • 一般都是少了分号的原因
  • 可以用分段注释的方法来解决

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/24138.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

哈夫曼树的创建

要了解哈夫曼树&#xff0c;可以先了解一下哈夫曼编码&#xff0c;假设我们有几个字母&#xff0c;他们的出现频率是A: 1 B: 2 C: 3 D: 4 E: 5 F: 6 G: 7。那么如果想要压缩数据的同时让访问更加快捷&#xff0c;就要让频率高的字母离根节点比较进&#xff0c;容易访问&#xf…

立创·天空星开发板-GD32F407VE-GPIO

本文以 立创天空星开发板-GD32F407VET6-青春版 作为学习的板子&#xff0c;记录学习笔记。 立创天空星开发板-GD32F407VE-GPIO 基础概念三极管MOS管 GPIO输出模式输出线与GPIO输入模式GPIO点灯 基础概念 GPIO&#xff0c;全称为“通用输入/输出”&#xff08;General Purpose …

算法金 | 这次终于能把张量(Tensor)搞清楚了!

大侠幸会&#xff0c;在下全网同名[算法金] 0 基础转 AI 上岸&#xff0c;多个算法赛 Top [日更万日&#xff0c;让更多人享受智能乐趣] 1. 张量&#xff08;Tensor&#xff09;基础概念 1.1 张量的定义与重要性 张量是深度学习中用于表示数据的核心结构&#xff0c;它可以视…

《帝国时代 III:决定版》秘籍 怎么在苹果电脑上玩《帝国时代 III:决定版》

《帝国时代 III&#xff1a;决定版》是一款让玩家沉浸于历史长河体验从大航海时代到工业革命时期的游戏。下面我们来看看《帝国时代 III&#xff1a;决定版》是什么类型的游戏&#xff0c;《帝国时代 III&#xff1a;决定版》Mac安装教程的相关内容。 一、《帝国时代 III&…

【BOM02】本地存储

一&#xff1a;什么是本地存储 数据存储在用户浏览器中&#xff0c;用户设置、读取方便&#xff0c;同时页面刷新时不会丢失数据。存储在浏览器中数据约5M&#xff0c;分为sessionStorage和localStorage两种存储方式 二&#xff1a;localStorage存储 作用 将数据永久存储在…

opencv实战小结-银行卡号识别

实战1-银行卡号识别 项目来源&#xff1a;opencv入门 项目目的&#xff1a;识别传入的银行卡照片中的卡号 难点&#xff1a;银行卡上会有一些干扰项&#xff0c;如何排除这些干扰项&#xff0c;并且打印正确的号码是一个问题 最终效果如上图 实现这样的功能需要以下几个步骤…

算法导论实战(三)(算法导论习题第二十四章)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;算法启示录 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 前言 第二十四章 24.1-3 24.1-4 2…

【Week-R2】使用LSTM实现火灾预测(tf版本)

【Week-R2】使用LSTM实现火灾预测&#xff08;tf版本&#xff09; 一、 前期准备1.1 设置GPU1.2 导入数据1.3 数据可视化 二、数据预处理(构建数据集)2.1 设置x、y2.2 归一化2.3 划分数据集 三、模型创建、编译、训练、得到训练结果3.1 构建模型3.2 编译模型3.3 训练模型3.4 模…

超详细的java Comparable,Comparator接口解析

前言 Hello大家好呀&#xff0c;在java中我们常常涉及到对象的比较&#xff0c;不同于基本数据类型&#xff0c;对于我们的自定义对象&#xff0c;需要我们自己去建立比较标准&#xff0c;例如我们自定义一个People类&#xff0c;这个类有name和age两个属性&#xff0c;那么问…

[数据集][图像分类]蘑菇分类数据集3122张215类别

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;3122 分类类别数&#xff1a;215 类别名称:[“almond_mushroom”,“amanita…

实验笔记之——DPVO(Deep Patch Visual Odometry)

本博文记录本文测试DPVO的过程&#xff0c;本博文仅供本人学习记录用~ 《Deep Patch Visual Odometry》 代码链接&#xff1a;GitHub - princeton-vl/DPVO: Deep Patch Visual Odometry 目录 配置过程 测试记录 参考资料 配置过程 首先下载代码以及创建conda环境 git clo…

有待挖掘的金矿:大模型的幻觉之境

人工智能正在迅速变得无处不在&#xff0c;在科学和学术研究中&#xff0c;自回归的大型语言模型&#xff08;LLM&#xff09;走在了前列。自从LLM的概念被整合到自然语言处理&#xff08;NLP&#xff09;的讨论中以来&#xff0c;LLM中的幻觉现象一直被广泛视为一个显著的社会…

Oracle EBS AP发票创建会计科目提示:APP-SQLAP-10710:无法联机创建会计分录

系统版本 RDBMS : 12.1.0.2.0 Oracle Applications : 12.2.6 问题症状: 提交“创建会计科目”请求提示错误信息如下: APP-SQLAP-10710:无法联机创建会计分录。 请提交应付款管理系统会计流程,而不要为此事务处理创建会计分录解决方法 数据修复SQL脚本: UPDATE ap_invoi…

LabVIEW阀性能试验台测控系统

本项目开发的阀性能试验台测控系统是为满足国家和企业相关标准而设计的&#xff0c;主要用于汽车气压制动系统控制装置和调节装置等产品的综合性能测试。系统采用工控机控制&#xff0c;配置电器控制柜&#xff0c;实现运动控制、开关量控制及传感器信号采集&#xff0c;具备数…

算法-分治策略

概念 分治算法&#xff08;Divide and Conquer&#xff09;是一种解决问题的策略&#xff0c;它将一个问题分解成若干个规模较小的相同问题&#xff0c;然后递归地解决这些子问题&#xff0c;最后合并子问题的解得到原问题的解。分治算法的基本思想是将复杂问题分解成若干个较…

计算机网络 期末复习(谢希仁版本)第3章

对于点对点的链路&#xff0c;目前使用得最广泛的数据链路层协议是点对点协议 PPP (Point-to-Point Protocol)。局域网的传输媒体&#xff0c;包括有线传输媒体和无线传输媒体两个大类&#xff0c;那么有线传输媒体有同轴电缆、双绞线和光纤&#xff1b;无线传输媒体有微波、红…

基于Texture2D 实现Unity 截屏功能

实现 截屏 Texture2D texture new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); texture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0); texture.Apply(); 存储 byte[] array ImageConversion.EncodeToPNG(texture); if (!…

分享万能点击器免费版,吾爱大佬出品,这个太赞了!

小伙伴们&#xff01;阿星又来给大家推荐神奇的小软件啦&#xff01;这次的主角可是个神器——鼠标连点器&#xff01;你听过没&#xff1f;这玩意儿简直是个“自动小助手”&#xff0c;让你的鼠标在屏幕上飞舞&#xff0c;点得飞快&#xff0c;解放你的双手&#xff0c;让你网…

一篇文章带你搞懂C++引用(建议收藏)

引用 6.1 引用概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间。 比如&#xff1a;李逵&#xff0c;在家称为"铁牛"&#xff0c;江湖上人称&quo…

Linux.软件操作

1.yum 命令 要连网 2.systemctl 命令控制软件的启动和关闭 3.ln 创建软连接 使用cat来找本体&#xff0c;看看链接生不生效 4.date 命令查看系统时间 格式化的时候可以用双引号把他们引出来 -d 对时间进行修改 修改时区 自动校准 手动校准 5.ifconfig 查看本机的ip地址 6.h…