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

【C++模拟实现】vector的模拟实现

【C++模拟实现】vector的模拟实现

目录

  • 【C++模拟实现】vector的模拟实现
      • vector模拟实现的标准代码
      • vector模拟实现中的要点
        • insert和erase会涉及到迭代器失效的问题
        • vector深度剖析
        • 关于模版template< class InputIterator >
        • 使用memcpy拷贝问题


作者:爱写代码的刚子

时间:2023.9.1

前言:模拟实现系列好久没更了,前来补更。

vector模拟实现的标准代码

namespace test
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator cbegin(){return _start;}const_iterator cend() const{return _finish;}vector():_start(nullptr),_finish(nullptr),_endOfStorage(nullptr){}vector(int n, const T& value = T()){resize(n,value);}template<class InputIterator>vector(InputIterator first, InputIterator last):_start(nullptr),_finish(nullptr),_endOfStorage(nullptr){//存疑,是否要reservewhile(first!=last){push_back(*first);++first;}}vector(const vector<T>& v)//这里是引用:_start(nullptr),_finish(nullptr),_endOfStorage(nullptr){reserve(v.capacity());for(auto e:v){push_back(e);}}vector<T>& operator= (vector<T> v){swap(v);return *this;}~vector(){delete[] _start;_start = nullptr;_finish = nullptr;_endOfStorage = nullptr;}size_t size() const{return _finish - _start;}size_t capacity() const{return _endOfStorage - _start;}void reserve(size_t n){if(n>capacity()) {iterator tmp = new T[n];//拷贝数据(手动)int sz = size();if(_start) {for (int i = 0; i < sz; i++) {tmp[i] = _start[i];}delete[] _start;//一定要记得}_start = tmp;_finish = _start + sz;_endOfStorage = _start + n;}}void resize(size_t n, const T& value = T()){if(n<capacity()){_finish=_start + n;}else{reserve(n);while(_finish!=_start+n){*_finish=value;++_finish;}}}T& operator[](size_t pos){assert(pos<size());return _start[pos];}const T& operator[](size_t pos)const{assert(pos<size());return _start[pos];}void push_back(const T& x){insert(end(),x);}void pop_back(){erase(--end());//注意是--end(),end()指向的是数据的下一个位置}void swap(vector<T>& v){std::swap(v._start,_start);std::swap(v._finish,_finish);std::swap(v._endOfStorage,_endOfStorage);}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 = _start + len;}iterator end = _finish - 1;while(end>=pos){*(end+1) = *end;--end;//--end不是++end()}*pos = x;++_finish;return pos;}iterator erase(iterator pos){assert(pos>=_start&&pos<=_finish);iterator it=pos+1;while(it!=_finish){*(it-1)=*it;++it;}--_finish;return pos;}private:iterator _start; // 指向数据块的开始iterator _finish; // 指向有效数据的尾iterator _endOfStorage; // 指向存储容量的尾};
}

vector模拟实现中的要点

insert和erase会涉及到迭代器失效的问题

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

有关迭代器失效的几种做法

  • 对于vector可能会导致其迭代器失效的操作有:

    1. 会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、 push_back等。

      出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉, 而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。

      解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新赋值即可。

    2. 指定位置元素的删除操作–erase

      erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。(但Linux下g++可能不一样,因为迭代器使用了原生指针,没有像vs一样进行封装)

**迭代器失效解决办法:在使用前,对迭代器重新赋值即可。 **

涉及到底层空间改变时,需要考虑重置迭代器

vector深度剖析

在这里插入图片描述

关于模版template< class InputIterator >

为什么不使用自己之前定义的iterator?

  • 若使用iterator做迭代器,会导致初始化的迭代器区间[first,last)只能是vector的迭代器
  • 重新声明迭代器,迭代器区间[first,last)可以是任意容器的迭代器

使用memcpy拷贝问题

为什么在reserve接口中不能直接使用memcpy进行拷贝?

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

所以在模版模拟实现中慎用memcpy!!!

结论:如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。


【附】:范围for是C++11的

相关文章:

【C++模拟实现】vector的模拟实现

【C模拟实现】vector的模拟实现 目录 【C模拟实现】vector的模拟实现vector模拟实现的标准代码vector模拟实现中的要点insert和erase会涉及到迭代器失效的问题vector深度剖析关于模版template< class InputIterator >使用memcpy拷贝问题 作者&#xff1a;爱写代码的刚子 …...

go学习part21(3)redis连接池

连接池 1.介绍 每次使用数据就就建立链接再关闭可以&#xff0c;但是如果有大量客户端频繁请求连接&#xff0c;大量创建连接和关闭会非常耗费资源。 所以就建立一个连接池&#xff0c;里面存放几个不关闭的连接&#xff0c;谁要用就分配给谁。 说明:通过Golang 对 Redis操…...

乐理-笔记

乐理笔记整理 1、前言2、认识钢琴键盘及音名3、升降号、还原号4、如何区分同一音名的不同键&#xff1f;5、各类音符时值的关系6、歌曲拍号7、拍号的强弱规律8、歌曲速度&#xff08;BPM&#xff09;9、附点音符10、三连音12、唱名与简谱数字13、自然大调&#xff08;白键&…...

java八股文面试[数据库]——B树和B+树的区别

B树是一种树状数据结构&#xff0c;它能够存储数据、对其进行排序并允许以O(logn)的时间复杂度进行查找、顺序读取、插入和删除等操作。 1、B树的特性 B树中允许一个结点中包含多个key&#xff0c;可以是3个、4个、5个甚至更多&#xff0c;并不确定&#xff0c;需要看具体的实…...

2、Nginx 安装

文章目录 2、Nginx 安装2.1 官网下载2.2 安装 nginx2.2.1 第一步2.2.2 第二步2.2.3 第三步&#xff0c;安装 nginx2.2.4 第四步&#xff0c;修改防火漆规则 【尚硅谷】尚硅谷Nginx教程由浅入深 志不强者智不达&#xff1b;言不信者行不果。 2、Nginx 安装 2.1 官网下载 nginx…...

最适合 AI 的 Python Web 框架

迷途小书童的 Note 读完需要 4分钟 速读仅需 2 分钟 1 简介 本文将介绍 Gradio 库&#xff0c;它是 Python 的一个 web 框架&#xff0c;可以帮助我们快速构建交互式 AI 应用。我们将了解 Gradio 的应用场景、基本原理、功能介绍&#xff0c;并通过一个代码示例来演示如何使用 …...

算法通关村第十八关——回溯

回溯很大感觉就是多重递归&#xff0c;在递归的题目中&#xff0c;例如斐波那契数列&#xff0c;只需要考虑当前情况以及他的子情况。而在回溯中&#xff0c;要进行很多次递归&#xff0c;并且要对条件进行处理。 LeetCode257:给你一个二叉树的根节点root,按任意顺序&#xff…...

使用kafka还在依赖Zookeeper,kraft模式了解下

Kafka的Kraft模式 概述 ​ Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。其核心组件包含Producer、Broker、Consumer&#xff0c;以及依赖的Zookeeper集群。其中Zookeeper集群是Kafka用来负责集群元数据的管理、控制器…...

【100天精通Python】Day52:Python 数据分析_Numpy入门基础与数组操作

目录 1 NumPy 基础概述 1.1 NumPy的主要特点和功能 1.2 NumPy 安装和导入 2 Numpy 数组 2.1 创建NumPy数组 2.2 数组的形状和维度 2.3 数组的数据类型 2.4 访问和修改数组元素 3 数组操作 3.1 数组运算 3.2 数学函数 3.3 统计函数 4 数组形状操作 4.1 重塑数组形…...

Day01-Java基础语法

目录 1. 人机交互 1.1 什么是cmd&#xff1f; 1.2 如何打开CMD窗口&#xff1f; 1.3 常用CMD命令 1.4 CMD练习 1.5 环境变量 2. Java概述 1.1 Java是什么&#xff1f; 1.2下载和安装 1.2.1 下载 1.2.2 安装 1.2.3 JDK的安装目录介绍 1.3 HelloWorld小案例 2.3.1 …...

代码随想录二刷day06

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣242. 有效的字母异位词二、力扣349. 两个数组的交集三、力扣202. 快乐数四、力扣1两数之和 前言 一、力扣242. 有效的字母异位词 class Solution {pub…...

可扩展的Blender插件开发汇总

成熟的 Blender 3D 插件是令人惊奇的事情。作为 Python 和 Blender 的新手,我经常发现自己被社区中的人们创造的强大的东西弄得目瞪口呆。坦率地说,其中一些包看起来有点神奇,当自我怀疑或冒名顶替综合症的唠叨声音被打破时,很容易想到“如果有人能做出可以做xxx的东西就好…...

2023_Spark_实验二:IDEA安装及配置

一、下载安装包 链接&#xff1a;百度网盘 请输入提取码 所在文件夹&#xff1a;大数据必备工具--》开发工具(前端后端)--》后端 下载文件名称&#xff1a;ideaIU-2019.2.3.exe &#xff08;喜欢新版本也可安装新版本&#xff0c;新旧版本会存在部分差异&#xff09; IDEA …...

小赢科技,寻找金融科技核心价

如果说金融是经济的晴雨表&#xff0c;是通过改善供给质量以提高经济质量的切入口&#xff0c;那么金融科技公司&#xff0c;就是这一切行动的推手。上半年&#xff0c;社会经济活跃程度提高背后&#xff0c;金融科技公司既是奉献者&#xff0c;也是受益者。 8月29日&#xff0…...

NAT与代理服务器

1.DNS Domain Name System 是一整套从域名映射到IP的系统&#xff08;把域名转化为IP地址&#xff09; 2.域名简介 3.周鸿祎 傅盛 4.ICMP协议 用来网络故障排查原因 草图理解“位置” ping ICMP 是绕过TCP UDP传输协议的&#xff0c;没有端口号 traceroute 5.NAT技术 N…...

24.排序,插入排序,交换排序

目录 一. 插入排序 &#xff08;1&#xff09;直接插入排序 &#xff08;2&#xff09;折半插入排序 &#xff08;3&#xff09;希尔排序 二. 交换排序 &#xff08;1&#xff09;冒泡排序 &#xff08;2&#xff09;快速排序 排序&#xff1a;将一组杂乱无章的数据按一…...

Navicat16安装教程

注&#xff1a;因版权原因&#xff0c;本文已去除破解相关的文件和内容 1、在本站下载解压后即可获得Navicat16安装包和破解补丁&#xff0c;如图所示 2、双击“navicat160_premium_cs_x64.exe”程序&#xff0c;即可进入安装界面&#xff0c; 3、点击下一步 4、如图所示勾选“…...

【看表情包学Linux】初识文件描述符 | 虚拟文件系统 (VFS) 初探 | 系统传递标记位 | O_TRUNC | O_APPEND

爆笑教程《看表情包学Linux》&#x1f448; 猛戳订阅&#xff01;​​​​​ &#x1f4ad; 写在前面&#xff1a;通过上一章节的讲解&#xff0c;想必大家已对文件系统基本的接口有一个简单的了解&#xff0c;本章我们将继续深入讲解&#xff0c;继续学习系统传递标志位&…...

ssm+vue“魅力”繁峙宣传网站源码和论文

ssmvue“魅力”繁峙宣传网站源码和论文102 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身…...

Linux系统编程5(线程概念详解)

线程同进程一样都是OS中非常重要的部分&#xff0c;线程的应用场景非常的广泛&#xff0c;试想我们使用的视频软件&#xff0c;在网络不是很好的情况下&#xff0c;通常会采取下载的方式&#xff0c;现在你很想立即观看&#xff0c;又想下载&#xff0c;于是你点击了下载并且在…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

flow_controllers

关键点&#xff1a; 流控制器类型&#xff1a; 同步&#xff08;Sync&#xff09;&#xff1a;发布操作会阻塞&#xff0c;直到数据被确认发送。异步&#xff08;Async&#xff09;&#xff1a;发布操作非阻塞&#xff0c;数据发送由后台线程处理。纯同步&#xff08;PureSync…...