手撕vector的模拟实现

𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary_walk

      ⸝⋆   ━━━┓
     - 个性标签 - :来于“云”的“羽球人”。 Talk is cheap. Show me the code
┗━━━━━━━  ➴ ⷯ

本人座右铭 :   欲达高峰,必忍其痛;欲戴王冠,必承其重。

👑💎💎👑💎💎👑 
💎💎💎自💎💎💎
💎💎💎信💎💎💎
👑💎💎 💎💎👑    希望在看完我的此篇博客后可以对你有帮助哟

👑👑💎💎💎👑👑   此外,希望各位大佬们在看完后,可以互相支持,蟹蟹!
👑👑👑💎👑👑👑


目录:
一 构造函数
二 析构函数
三 size( )
四 capacity( )
五 reserve ()
六 resize ()
七 push_back()
八 insert()
九 erase()
十迭代器相关函数模拟

其实对于vector 模拟实现的学习和前面的string 是一样滴,学起来简直就是 so easy!

 首先需要我们对vector 这个类有一定的了解

其实vector 就是数据结构里面的顺序表

vector 里面有三个重要的指针,以下所有的模拟实现都是基于当前这三个指针进行滴,所以对着三个指针必须要深入了解

 结合草图进行理解:

 为了避免和库里面的vector 发生冲突,我把自己实现的vector 这个类放在一个命名空间里面

定义一个vector类:

1: 构造函数

 1)无参构造函数
vector()//无参构造函数:_start(nullptr),_finish(nullptr),_enofstorage(nullptr){}

 之所以选择对_start   _finish  _enofstorage 这三个指针进行初始化为空,就是避免在后面调用析构函数的时候导致程序崩溃

2)有参构造函数

1) 用 n 个 val 进行实例化

vector(size_t n, const T& val){reserve(n);for (size_t i = 0; i < n; i++)push_back(val);}

 2)迭代器区间进行初始化:注意是可以在一个类里面再写一个模板的

template <class InputIterator>// 在一个类模板里面是支持在写一个模板函数的vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}

 各位老铁看一下,下面问题是咋回事???

问题:

当对v2这个对象进行调用构造函数的时候,是可以编译通过的;但是当对v1这个对象进行构造函数调用的时候编译失败。

分析:

v2这个对象对应调用构造函数的参数的类型是 int ,string 类型,此时编译器会自动匹配最佳的函数,所以直接调用第2个构造函数;但是对于v1这个对象的调用构造函数的参数类型是 int ,int 类型此时编译器只会直接匹配第一个构造函数,之所以不匹配第2个构造函数是因为:要进行整型的提升,那编译器还不如直接走第一个构造函数的调用,但是此时的参数是int 类型不能进行解引用的所以编译器报错:非法的间接寻址

 

解决:

咱直接搞一个构造函数参数的类型是int  int  类型的不就OK了

 3)赋值运算符重载
	void swap(vector<T>& tmp){std::swap(_start, tmp._start);std::swap(_finish, tmp._finish);std::swap(_endofstoreage, tmp._endofstoreage);}vector<T>& operator=(vector<T>& tmp){swap(tmp);return *this;}
 4)[ ] 运算符重载
	T& operator[] (const size_t pos){assert(pos < size());//防止越界return _start[pos];}const T& operator[] (const size_t pos) const{assert(pos < size());//防止越界return _start[pos];}

2: 析构函数
~vector(){delete[] _start;_start = _finish = _enofstorage = nullptr;}
3:size( )
	size_t size(){return _finish - _start;//返回当前有效的数据个数}
4: capacity( )
	size_t capacity(){return _enofstorage - _start;//返回当前的空间容量}
5:reserve ()
reserve()坑点一:野指针

注意:这个是错误的代码

 分析:

 对当下问题的纠正:

reserve()坑点二:浅拷贝

借助对象v1 对v2进行实例化,以下程序会崩溃

 分析:

此时2个不同对象指向同一块空间,在调用析构函数的时候,v2这个对象先销毁(符合先创建的对象后析构),当v1调用析构函数的时候,此时所指向的空间已经归还系统,因此出现野指针,造成程序的崩溃

问题的本质:memcpy()这个函数在进行拷贝的时候是值拷贝(不管是内置类型还是自定义类型数据)

 解决:对数据进行深拷贝

//memcpy(tmp, _start, sizeof(T) * size());//err 浅拷贝for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}
正确代码:
	void reserve(size_t n){if (n > capacity()){size_t sz = size();//提前记录扩容之前的size()T* tmp = new T[n];// 数据拷贝if (_start){//memcpy(tmp, _start, sizeof(T) * size());//err 浅拷贝for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete _start;}//更新_start = tmp;_finish = _start + sz;_enofstorage = _start + n;}}
6:resize ()

 正确代码:

思考以下几个问题:

1) 为什么要调用构造函数进行指定的初始化 直接默认用0进行初始化不OK???     

2)可以不用引用吗

 1)之所以使用构造函数进行初始化是因为,并不确定当下T的类型是否为int,还是其他类型:char   vector<vector<int>>……

2)可以不使用引用第二个参数这样写也是OK的

const  T val =  T()

7: push_back()
void push_back(const T& v){// 是否扩容// _finish 进行++if (_finish == _enofstorage){size_t sz = size();//记录扩容之前的size() 避免后续野指针的出现size_t cp = capacity() == 0 ? 4 : 2 * capacity();T* tmp = new T[cp];delete[]_start;//旧空间释放if(_start)// 数据拷贝{memcpy(tmp, _start, sizeof(T) * size());}// 扩容之后的更新_start = tmp;_finish = _start + sz;_enofstorage = _start + cp;}//数据插入*(_finish) = v;++_finish;}
8:insert()

相信有很多老铁们会这样写代码吧(俺一开始就是这样搞滴)

错误代码:

 遇到问题不慌不忙,咱调试走起,瞧瞧咋回事

 分析:

 通过调试我们发现,在没有扩容之前程序是可以正常跑起来的,但是当涉及到扩容时,就出现了随机值在。

其实这就是我们所说的迭代器的内部失效的问题,要想再对迭代器更改后进行使用,我们可以记录一下pos 迭代器相对于起始位置的偏移量,下一次再使用的时候对pos 迭代器进行更新即可

 运行结果:

正确代码:

void insert(iterator  pos, const T& val){//默认pos 位置之前进行插入// pos 位置是否合法// 是否扩容assert(pos >= _start);assert(pos < _finish);if (_finish == _enofstorage){size_t sz = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());pos = sz + _start;//更新迭代器}iterator end = _finish;while (end > pos){*end = *(end - 1);--end;}*pos = val;++_finish;}
9: erase()

咱话不多说,代码先跑起来,康康!

可能有的老铁看到当前的运行结果觉得很满意:不错不错是我预期的(试过了各个位置的删除)

但是:也有些敏锐的老铁,会觉得有了上面insert()函数给我们的经验,erase() 函数也会涉及到迭代器实失效的问题

 通过以下程序的分析结果变可以看出:

 正确代码:
	void erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);//数据覆盖vector<int>::iterator end = pos + 1;while (end < _finish){*(end - 1) = *end;++end;}--_finish;}while (pos != v1.end()){if (*pos % 2 == 0)v1.erase(pos);// 删除之后自然返回挪动数据之后的对应位置的迭代器,从而避免连续偶数的时候有没有删掉的else{++pos;}}

运行结果:

 通过对insert() erase() 调用我们发现:都会出现迭代器失效的问题

10:迭代器相关函数模拟
typedef T* iterator; // 默认受到类域的限制,所以默认属性是privatetypedef const T* const_iterator;iterator _start;  // 指向数据的起始位置iterator _finish; // 指向最后一个数据的下一个位置iterator _enofstorage;// 指向剩余容量的末尾位置//迭代器相关实现iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin()const{return _start;}const_iterator end()const{return _finish;;}
结语:以上就是要share 的内容,对于初次模拟实现vector的小白而言,还是多多少少有些坑注定少不了的,所以说咱也不要害怕踩坑。其实对这个vector模拟实现重点就是迭代器相关的使用以及理解,所以说咱还是多多敲敲代码,看看stl库里面相关的资料介绍,希望各位大佬们都有所收获!

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

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

相关文章

华为云耀云服务器开放端口

博客主页&#xff1a;花果山~程序猿-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 一.华为云控制台开放端口 寻找到安全组信息 2. 添加开放的端口信息 3. 检查是否成…

视频编辑软件pitivi基本功之将三个相关视频合并成一个视频

视频编辑软件pitivi基本功之将三个相关视频合并成一个视频 一、素材来源&#xff1a;网站下载 到http://cpc.people.com.cn/GB/67481/435238/437822/437828/437900/index.html下载以下三个视频&#xff0c;鼠标右击视频——另存视频为 庆祝中国共产党成立100周年大会即将开始—…

【开源物联网平台】window环境下搭建调试监控设备环境

&#x1f308; 个人主页&#xff1a;帐篷Li &#x1f525; 系列专栏&#xff1a;FastBee物联网开源项目 &#x1f4aa;&#x1f3fb; 专注于简单&#xff0c;易用&#xff0c;可拓展&#xff0c;低成本商业化的AIOT物联网解决方案 目录 一、使用docker脚本部署zlmediakit 1.1 …

学习中遇到的问题

1.UFUNCTION() 不是所有函数都能加UFUNCTION()修饰&#xff0c;涉及UE反射机制。 2.初始化用{} 初始化列表 3.创建C文件时修改了路径 这时.cpp文件会报错&#xff0c;只需删掉前面多余路径即可

npm install报错

总结&#xff1a;没有安装visual studio 2017以上带有C桌面开发的版本 #开始试错 #报错总信息mingw_x64_win版本 百度网盘链接: link 提取码&#xff1a;3uou #尝试用mingw配置个C编译器&#xff0c;并配置环境变量&#xff0c;失败 #只认可使用VS!GIthub原址: 链接: link 上…

Java_JVM_JVMs

JVM 官方文档说明文档目录 官方文档 JVM Specification 说明 以Java SE 17为标准 文档目录 2&#xff1a;JVM 结构 class文件数据类型 基本数据类型引用数据类型 运行时数据区 栈帧 其他内容 对象的表示浮点数运算特殊方法 初始化方法【实例、类】多态方法 3&#xff…

IDEA 创建Servlet-HelloWorldServlet

servlet 1.创建空项目2.配置web项目3.配置Tomcat4.加载Tomcat包5.创建HelloWorldServlet类6.配置web.xml7.运行get与post请求 1.创建空项目 2.配置web项目 3.配置Tomcat 4.加载Tomcat包 5.创建HelloWorldServlet类 public class controller extends HttpServlet {Override//get…

yolov5-pytorch-Ultralytics训练+预测+报错处理记录

一、前言 玩一段时间大模型&#xff0c;也该回归一下图像识别。本项目用于记录使用基于Ultralytics的yolov5进行目标检测测试。为什么用Ultralytics呢&#xff1f;答案有3 1、其良好的生态&#xff0c;方便我们部署到其它语言和设备上。因此本次测试结论&#xff1a;大坑没有&…

第四篇:记忆的迷宫:探索计算机存储结构的奥秘与创新

记忆的迷宫&#xff1a;探索计算机存储结构的奥秘与创新 1 引言 1.1 计算机存储系统的发展与重要性 在现代计算技术中&#xff0c;存储系统承担着非常关键的角色&#xff0c;它不仅负责信息的持久保存&#xff0c;同时确保高效的数据访问速度&#xff0c;影响着整体系统性能的…

题目:线性代数

问题描述&#xff1a; 解题思路&#xff1a; 列相乘&#xff0c;然后行相加。 注意点&#xff1a;由于元素数据范围最大为1e6&#xff0c;两个元素相乘乘积最大为1e12&#xff0c;如果元素类型为int则在乘的过程中就会爆炸&#xff0c;所以需要开long long类型。 AC代码…

【大语言模型LLM】-基于大语言模型搭建客服助手(2)

&#x1f525;博客主页&#xff1a;西瓜WiFi &#x1f3a5;系列专栏&#xff1a;《大语言模型》 很多非常有趣的模型&#xff0c;值得收藏&#xff0c;满足大家的收集癖&#xff01; 如果觉得有用&#xff0c;请三连&#x1f44d;⭐❤️&#xff0c;谢谢&#xff01; 长期不…

ABAP 数据写入Excel 并保存

参考老白 https://www.cnblogs.com/liaojunbo/archive/2011/09/06/2168552.html 但是缺zcl_excel 。需要从 dotabap要引入abap2xlsx 英文版进入后 尝试了一下 1&#xff09;列的宽度自适应么有找到在哪里&#xff1f; 列宽设置 lo_worksheet->set_column_width( ip_co…

nuxt3使用记录六:禁用莫名其妙的Tailwind CSS(html文件大大减小)

发现这个问题是因为&#xff0c;今天我突然很好奇&#xff0c;我发现之前构建的自动产生的200.html和404.html足足290k&#xff0c;怎么这么大呢&#xff1f;不是很占用我带宽&#xff1f; 一个啥东西都没有的静态页面&#xff0c;凭啥这么大&#xff01;所以我就想着手动把他…

OpenWRT有线桥接部署教程

前言 之前咱们讲到OpenWRT部署WAN实现PPPoE拨号上网和自动获取IP模式上网的办法&#xff1a; OpenWRT设置PPPoE拨号教程 OpenWRT设置自动获取IP&#xff0c;作为二级路由器 这一次&#xff0c;咱们尝试用OpenWRT有线桥接上一级路由器的教程。 可能有小伙伴敏锐地发现了&am…

【软件工程】详细设计

目录 前言详细设计算法设计工具——判定表 前言 软件工程生命周期分为八个阶段&#xff1a; 问题定义—>可行性研究—>需求分析 —>概要设计—>详细设计—>编码与单元测试 —>综合测试—>软件维护 这节我们讲的是软件开发流程中的一个阶段&#xff0c;需求…

Docker-Compose编排LNMP并部署WordPress

前言 随着云计算和容器化技术的快速发展&#xff0c;使用 Docker Compose 编排 LNMP 环境已经成为快速部署 Web 应用程序的一种流行方式。LNMP 环境由 Linux、Nginx、MySQL 和 PHP 组成&#xff0c;为运行 Web 应用提供了稳定的基础。本文将介绍如何通过 Docker Compose 编排 …

C语言 | Leetcode C语言题解之第66题加一

题目&#xff1a; 题解&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* plusOne(int* digits, int digitsSize, int* returnSize){for(int i digitsSize - 1; i > 0; --i){digits[i] digits[i] 1;//最后元素1判断是不…

ssh远程访问windows系统下的jupyterlab

网上配置这一堆那一堆&#xff0c;特别乱&#xff0c;找了好久整理后发在这里 由于既想打游戏又想做深度学习&#xff0c;不舍得显卡性能白白消耗&#xff0c;这里尝试使用笔记本连接主机 OpenSSH 最初是为 Linux 系统开发的&#xff0c;现在也支持包括 Windows 和 macOS 在内…

开源博客项目Blog .NET Core源码学习(20:App.Hosting项目结构分析-8)

本文学习并分析App.Hosting项目中后台管理页面的个人资料页面、修改密码页面。 个人资料页面 个人资料页面用于显示和编辑个人信息&#xff0c;支持从本地上传个人头像。整个页面使用了layui中的表单、日期与时间选择、上传等样式或模块&#xff0c;通过layui.css文件设置样式…

Rust Web开发实战:打造高效稳定的服务端应用

Rust Web开发实战&#xff1a;打造高效稳定的服务端应用 本书将带领您从零开始构建Web应用程序&#xff0c;无论是API、微服务还是单体应用&#xff0c;都将一一涵盖。您将学到如何优雅地对外开放API&#xff0c;如何连接数据库以安全存储数据&#xff0c;以及如何对应用程序进…