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

【c++】vector的使用与模拟实现

在这里插入图片描述

🚀write in front🚀
📜所属专栏:初阶数据结构
🛰️博客主页:睿睿的博客主页
🛰️代码仓库:🎉VS2022_C语言仓库
🎡您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!
关注我,关注我,关注我你们将会看到更多的优质内容!!

在这里插入图片描述

文章目录

  • 前言
  • 一.vector和string的区别:
  • 二.vector的使用:
  • 三.vector的模拟实现:
    • 1.vector的成员变量:
    • 2.vector的迭代器问题(重点):
      • insert()函数:
      • erase()函数:
      • insert的迭代器失效:
      • erase的迭代器失效:
      • string的迭代器失效:
    • 3.vector深浅拷贝问题:
    • 4.vector构造函数问题:
  • 总结
  • 总结

前言

  在学习完string之后,我们来开始vector的学习,其实vector的各个函数和string是非常类似的,所以我们就着重讲讲vector的易错点就行了。

一.vector和string的区别:

  vector是可变大小数组的序列容器,可以存储任意相同类型的元素。而string是专门用来存储字符串的。当然,我们不能用vector<char>来代替string,因为string存在着’\0’的问题,并且string的有些函数是专门针对字符串的,而vector没有。

二.vector的使用:

  在这里参考文档就可以了:vector使用介绍
  当然对于二维数组,我们就不得不说vector的优势了。在学习c语言时,对于二维数组,我们每一行每一列的大小的空间都是定死的,而如果我们使用vector<vector<int>>就可以灵活使用。
在这里插入图片描述
  在看完vector的使用文档我们就可以明白里面的原理:
在这里插入图片描述

三.vector的模拟实现:

  在这里我们就就讲讲和string不同的地方即可,其他地方和string都是类似的。

1.vector的成员变量:

通过查看strl的vector(stl的原代码实现)实现我们可以看出,vector的成员变量和string的是不太一样的:
在这里插入图片描述
  由此可见,vector的成员变量是通过三个指针来实现的。他们分别指向数组的开头,数组的有效尾部和数组的容量尾部。
在这里插入图片描述

2.vector的迭代器问题(重点):

  迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,然而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。

insert()函数:

iterator insert(iterator pos, const T& x){assert(pos >= _start && pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);// 解决pos迭代器失效问题pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;}

erase()函数:

iterator erase(iterator pos){assert(pos >= _start && pos < _finish);iterator it = pos + 1;while (it != _finish){*(it - 1) = *it;++it;}--_finish;return pos;}

insert的迭代器失效:

  会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resizereserveinsertassignpush_back等。
如果我们使用以下代码就会发现出错:

		vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(5);v1.push_back(5);v1.push_back(5);auto pos=v1.begin();v1.insert(pos);v1.insert(pos+1);

  这里迭代器失效的原因想必大家都知道,在扩容之后,成员变量的三个指针指向的空间发生了改变,此时我们pos就变成了一个野指针。所以此时我们的迭代器失效了。

erase的迭代器失效:

  erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了

  vs编译器为了防止这些现象的发生,就对迭代器进行了极端处理:在insert或erase使用了迭代器对象之后,不能在访问这个迭代器,vs认为他是失效,访问是未定义。

  然而,在Linux的g++下面不存在这样的强制检查,有时候使用也是对的,但是这样的话就不符合代码的可移植性了。

  这就是为什么我们在模拟实现的时候会返回一个迭代器,就是为了给这个迭代器重新赋值:

```cppvector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(5);v1.push_back(5);v1.push_back(5);auto pos=v1.begin();pos=v1.insert(pos);pos=v1.insert(pos+1);

这样就不会出错了。

string的迭代器失效:

  与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效

  总结一下,为了防止迭代器失效,在使用迭代器前,对迭代器重新赋值即可.

3.vector深浅拷贝问题:

  假设模拟实现的vector中的reserve接口中,使用memcpy进行的拷贝,以下代码会发生什么问题?

		vector<string> v1;v1.push_back("edd");v1.push_back("werewedf");v1.push_back("sddeedf");v1.push_back("sdwdf");v1.push_back("Sdfef");

我们先来复习一下memcpy的性质:

  • memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
  • 如果拷贝的是自定义类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。

由此可见,在reserve里面如果使用memcpy函数,在vector这个类型里面,此时的复制就是浅拷贝。由于两个string指向同一个空间,在析构函数释放的时候就会出现问题。
在这里插入图片描述
在这里插入图片描述

那么我们怎么解决这个问题呢?
在这里插入图片描述
因为不同的类不一样,我们不可能对于string单独写一个,list之类的也存在浅拷贝问题,所以我们直接使用string类的赋值重载来实现string对象的深拷贝:
在这里插入图片描述
在这里插入图片描述

4.vector构造函数问题:

  同学们在看vector构造函数的时候可能会看到这里:
在这里插入图片描述
随后便想自己模拟实现一下,但是这里的迭代器类型和模板类的迭代器类型可能不一样,比如当我们用string类来初始化vector的时候。

	string str("你干嘛哈哈");vector<char>(str.begin(),str.end());//在这里迭代器不同。

所以我们要通过模板类里面在套模板来实现:

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

总结

  总的来说,在学完string以后学习vector还是比较轻松的。这里是模拟实现的完整代码:vector模拟实现

总结

  更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

专栏订阅:
每日一题
C语言学习
算法
智力题
初阶数据结构
Linux学习
C++学习
更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

在这里插入图片描述

相关文章:

【c++】vector的使用与模拟实现

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;初阶数据结构 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对…...

记录安装stable diffusion webui时,出现的gfpgan安装卡住的问题

参考链接&#xff1a;(145条消息) 使用stable diffusion webui时&#xff0c;安装gfpgan失败的解决方案&#xff08;windows下的操作&#xff09;_新时代原始人的博客-CSDN博客...

【开发环境】Windows下搭建TVM编译器

关于搭建TVM编译器的官方文档&#xff1a;Install from Source — tvm 0.14.dev0 documentation (apache.org) 1. 安装Anaconda 首先我们需要安装Anaconda&#xff0c;因为其中包含着我们所需要的各类依赖&#xff1a; 进入Anaconda官网https://www.anaconda.com/products/d…...

了解Unity编辑器之组件篇Video(二)

Video Player组件&#xff1a;用于在游戏中播放视频的组件。它提供了一系列属性来控制视频的播放、显示和交互。 1.Source&#xff08;视频源&#xff09;&#xff1a;用于指定视频的来源。可以选择两种不同的视频源类型&#xff1a; &#xff08;1&#xff09;Vieo Clip&#…...

安全杂记 - 状态码,DNS,编码

目录 1.状态码2.DNS解析过程3.URL编码4.HTML实体编码5.FORM表单 1.状态码 200 - 请求成功 301 - 资源&#xff08;网页等&#xff09;被永久转移到其它URL 302 - 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI 304 - 未修改。所请求的资源未修改&#…...

微信小程序 Page页面

新建页面只需要在app.json配置好路径&#xff0c;编译器自动新增了页面 项目首页&#xff0c;在app.json哪个页面是第一位&#xff0c;哪个页面就是小程序首页...

C语言实现基于Linux,epoll和多线程的WebServer服务器

代码结构&#xff1a; Server.h 头文件&#xff0c;对函数进行了声明 #pragma once #include<stdio.h> // 新建一个用于TCP监听的socket文件描述符&#xff0c;并返回 int initListenFd(unsigned short port);// 启动epoll int epollRun(int lfd);// accept建立连接 vo…...

微信小程序数字键盘(仿微信转账键盘)

微信小程序input自带数字输入键盘&#xff0c;不过是直接调用的系统键盘&#xff0c;无法个性化。 代码中使用使用了Vant WeappVant UI小程序版&#xff0c;这里就不介绍相关安装说明了&#xff0c;大家自行安装Vant Weapp。 json 用到的组件 {"usingComponents": …...

mac电脑强大的解压缩软件BetterZip 5.3.4 for Mac中文版及betterzip怎么压缩

BetterZip 5.3.4 for Mac 是Mac系统平台上一款功能强大的文件解压缩软件&#xff0c;不必解压就能快速地检查压缩文档。它能执行文件之间的合并并提供密码。使用它&#xff0c;用户可以更快捷的向压缩文件中添加和删除文件。它支持包括zip、gz、bz、bz2、tar、tgz、tbz、rar、7…...

Llama 2 来袭 - 在 Hugging Face 上玩转它

&#x1f917; 宝子们可以戳 阅读原文 查看文中所有的外部链接哟&#xff01; 引言 今天&#xff0c;Meta 发布了 Llama 2&#xff0c;其包含了一系列最先进的开放大语言模型&#xff0c;我们很高兴能够将其全面集成入 Hugging Face&#xff0c;并全力支持其发布。Llama 2 的社…...

linux操作历史history定制

history记录 Linux中历史操作记录history是一个很有用的功能&#xff0c;有时忘记了&#xff0c;翻翻以前的命令&#xff0c;十分方便。 # 展示所有历史记录 history # 筛选历史记录 history | grep nginx # 清除全部记录 -c history -c # 指定删除某一行,15是行号 history -…...

微信小程序 wx.showModal

微信小程序--wx.showModal_海轰Pro的博客-CSDN博客...

Java开发中的分层开发和整洁架构

分层开发(横向拆分) 分层开发的概念: maven多模块开发项目管理.可以利用这种管理功能,实现一个项目的多层次模块开发–分层开发. 比如,当前项目HelloController依赖HelloService 这样做目的: 复杂开发过程.解耦(不调整依赖关系,无法解耦).分层开发(横向拆分)和纵向拆分的区别…...

Spring 多数据源方法级别注解实现

Spring框架提供了多种数据源管理方式&#xff0c;其中多数据源管理是其中之一。多数据源管理允许应用程序使用多个数据源&#xff0c;而不是只使用一个数据源&#xff0c;从而提高了应用程序的灵活性和可靠性。 多数据源管理的主要目的是让应用程序能够在不同的数据库之间切换&…...

Redis在云服务器上的安装与客户端连接配置

文章目录 Redis1.Redis的安装2.设置远程连接3.客户端连接3.1 客户端下载 Redis 1.Redis的安装 yum 安装 redis&#xff0c;使用以下命令&#xff0c;直接将 redis 安装到 linux 服务器&#xff1a; yum -y install redis 启动 redis使用以下命令&#xff0c;以后台运行方式启…...

​语言模型输出端共享Embedding的重新探索

©PaperWeekly 原创 作者 | 苏剑林 单位 | 科学空间 研究方向 | NLP、神经网络 预训练刚兴起时&#xff0c;在语言模型的输出端重用 Embedding 权重是很常见的操作&#xff0c;比如 BERT、第一版的 T5、早期的 GPT&#xff0c;都使用了这个操作&#xff0c;这是因为当模型…...

Spring中事务失效的8中场景

1. 数据库引擎不支持事务 这里以 MySQL为例&#xff0c;MyISAM引擎是不支持事务操作的&#xff0c;一般要支持事务都会使用InnoDB引擎&#xff0c;根据MySQL 的官方文档说明&#xff0c;从MySQL 5.5.5 开始的默认存储引擎是 InnoDB&#xff0c;之前默认的都是 MyISAM&#xff…...

安卓——转场动画

先创建一个名为anim的包 往里面写入两个xml页 为淡入淡出的效果 淡入效果 <alpha xmlns:android="http://schemas.android.com/apk/res/android"android:interpolator="@android:anim/accelerate_decelerate_interpolator"android:fromAlpha...

多位数码管动态扫描显示变化数据(数码管右移1)

/*----------------------------------------------- 内容&#xff1a;多位数码管分别显示不同数字&#xff0c;这种扫描显示方式成为动态扫描&#xff0c;并不停变化赋值 ------------------------------------------------*/ #include<reg52.h> //包含头文件&#xff0…...

充分了解java阻塞队列机制

多线程基础 1.阻塞队列1.1 什么是 阻塞队列1.2 阻塞队列的特点 1.3 阻塞队列常用方法1.3.1 抛出异常:add、remove、element1.3.2 返回结果但是不抛出异常offer、poll、peek1.3.3 阻塞put和take1.3.4 小结 1.4 常见的阻塞队列1.4.1 ArrayListBlockingQueue1.4.2 LinkedBlockingQ…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...