探索C++中的动态数组:实现自己的Vector容器

请添加图片描述

🎉个人名片

🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🙈个人主页🎉:GOTXX
🐼个人WeChat:ILXOXVJE
🐼本文由GOTXX原创,首发CSDN🎉🎉🎉
🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路
🐓每日一句:如果没有特别幸运,那就请特别努力!🎉🎉🎉
————————————————

🎉文章简介

🎉本篇文章将 介绍如何使用C++编写代码来实现一个类似于STL中的Vector容器 等学习的相关知识进行分享!

💕如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加 油,一起奔跑,让我们顶峰相见!!!🎉🎉🎉
——————————————————————————

一.前言

这篇文章将介绍如何使用C++编写代码来实现一个类似于STL中的Vector容器。Vector是一种动态数组,它可以根据需要自动调整大小,并提供了许多方便的方法来操作数据。在这篇文章中,你将学习如何使用指针和动态内存分配来创建一个可变大小的数组,并实现Vector的常见功能,如添加元素、删除元素、访问元素等。通过实现自己的Vector容器,你将更好地理解动态数组的原理和实现方式,并提升对C++语言的理解和掌握。

二.Vs下Vector的底层结构

vs下底层是一个类,类里面的成员变量包括三个指针,指针类型为所存储数据类型(T)的指针;
T* _start 指向的是存储数据所开空间的起始位置;
T* _finish 指向的是最后一个数据的下一个位置;
T* _endofstorage 指向的是所开空间的最后的下一个位置;

如图:
在这里插入图片描述

public:typedef T* iterator;typedef const T* const_iterator;
private:iterator _start;iterator _finish;iterator _endofstorage;

三.vector的模拟实现

1.构造函数

1.直接初始化为空指针,使用时再开空间

vector():_start(nullptr),_finish(nullptr)         //也可以在定义的时候直接给缺省值,_endofstorage(nullptr)
{}

2.用一个迭代器区间构造(需要复用下面实现的push_back函数)

	template<class intputiterator>     //模板vector(intputiterator first, intputiterator last){while (first != last)  //不能是用<判断,因为底层不一定连续{push_back(*first);    //依次取里面的数据尾插++first;}}

3.用n个T类型构造对象(这里需要后面实现的resize函数)

vector(size_t n,const T& x = T())
{resize(n,x);
}
vector(int n, const T& x = T())
{resize(n,x);
}

注意:这里为什么要实现两个?
在这里插入图片描述

2.reserve函数

结合下面代码和图解看看思路解析:
1.reserve函数可以单独使用,也可以在其他接口种会使用,我们实现的该函数不会缩容,所以最开始会加一个判断是否缩容;
2.reserve函数的实现是开一个新空间,将原空间的数据拷贝到新空间,再对_start,_finish,_endofstorage 进行处理;
3.这里需要记录一个原空间存储的有效数据的个数,为了确定_finish的位置(如果不存储,则当开辟好了新空间后,_finish的位置不能确定)
图解:
在这里插入图片描述

void reserve(size_t n)
{if (n > capacity()){size_t old_size = size();      //旧空间有效数据个数size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();   //需要判断,因为可能为0iterator tmp = new T[newcapacity];     //开空间//memcpy(tmp, _start,old_size * sizeof(T));   //下面会将为什么不用memmove函数for (int i = 0; i < old_size; i++){tmp[i] = _start[i];       //拷贝数据}delete[] _start;             //释放旧空间_start = tmp;_finish = _start + old_size;      //确定_finish的位置_endofstorage = _start + newcapacity;     }
}

为什么不用memmove?
当我们存储的数据类型为string时【如图一】每个string对象里面都有一个_str,指向一个字符串,当我们用memmove拷贝后,拷贝后的_str与拷贝前的_str指向同一块空间【如图二】,当我们释放_start的时候,会调用string的析构函数,将该空间释放掉,就会导致野指针问题;

在这里插入图片描述

3.push_back函数

思路:检查是否空间满了,扩容,直接尾插

	void push_back(const T& x){if (_finish == _endofstorage)    //检查是否需要扩容{reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = x;     //尾插++_finish;    //更新下标}

4.push_back函数

思路:与顺序表实现一样,直接–_finish;

void pop_back()
{assert(size());   //检查是否还有有效数据可删--_finish;
}

5.resize函数

思路:
分为三种可能:
1.n>capacity 扩容+尾插
2.size<n<capacity 直接尾插
3.n<size 尾删

值得注意的是传参给了缺省值,因为存储数据可能是string这种数据,给了缺省值会去掉对应的默认构造函数,虽然内置类型没有默认构造,但是为了解决这类问题,有了类似于默认构造类处理内置类型;

void resize(size_t n,T x=T() )   {if (n<size())     //直接改变_finish{_finish = _start + n;;}else{if (n > capacity())   //扩容{reserve(n);}for (size_t i = size(); i <= n; i++)  //尾插{_start[i] = x;      //可以复用push_back函数}_finish = _start + n;    //更新}}

6.insert函数

思路:
1.检查是否需要扩容
2.挪动数据
3.插入,更新下标

iterator insert(iterator pos, const T& x)
{assert(pos);assert(pos >= _start);     //断言assert(pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;              //记录之前的值reserve(capacity() == 0 ? 4 : 2 * capacity();    //扩容pos = _start + len;          //更新pos下标}//memmove(pos+1, pos, sizeof(T) * (_finish - pos));  iterator end = _finish-1;while (end>=pos){*(end+1) = *end;     //拷贝end--;}*pos = x;     //插入++_finish;    return pos;    //返回pos位置的迭代器,防止迭代器失效问题
}

7.erase函数

直接挪动数据覆盖

	iterator erase(iterator pos){assert(pos < _finish && pos >= _start);   //断言iterator end = pos;while (end < _finish){*end = *(end + 1);   //挪动数据覆盖end++;}--_finish;          //更新下标return pos;      //返回pos位置的迭代器,防止迭代器失效问题}

8.swap函数

void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage,v._endofstorage);}

9.赋值运算符重载

与上章《魔法之线:探索string类的神秘世界》链接: link赋值运算符重载方法一样;

现代写法:

	vector<T>& operator=(vector<T> v){swap(v);      return *this;}

10.拷贝构造函数

传统写法:

	vector(const vector<T>& v){iterator tmp = new T[v.capacity()];memcpy(tmp, v._start, sizeof(T) * v.size());_start = tmp;_finish = _start + v.size();_endofstorage = _start + v.capacity();}

稍便捷的方式
直接复用尾插函数,将对象v的数据一个一个尾插;

		vector(vector<T>& v):_start(nullptr),_finish(nullptr),_endofstorage(nullptr){reserve(v.capacity());      //提前空间,减少尾插扩容for (const auto& e : v){push_back(e);}}

11.其他简单函数的实现:

		//判空bool empty(){return size();}//返回第一个数据T& front()const{return *_start;}//返回最后一个数据T& back()const{return *(_finish-1);}//返回有效数据个数size_t size()const{return _finish - _start;}//返回容量size_t capacity()const{return _endofstorage - _start;}//[]运算符重载T& operator[](size_t pos){assert(pos>=0 && pos<size());return _start[pos];}T& operator[](size_t pos)const{assert(pos >= 0 && pos < size());return _start[pos];}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin()const{return _start;}const_iterator end()const{return _finish;}~vector(){if(_start)delete[] _start;_start = _finish = _endofstorage = nullptr;}

💕最后希望内容对大家有所帮助😊😊😊

请添加图片描述

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

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

相关文章

echarts line绘制机组开关状态折线图

2024.3.12今天我学习了如何用echarts line实现设备开关状态的效果。 代码如下&#xff1a; option {xAxis: {type: time,},yAxis: {type: value,splitNumber:2,// axisLine: {// show: true,// lineStyle: {// color:#808080// }// },axisLabel:{formatt…

管控员工上网行为(让老板管理更省心更高效)

很多老板都有这样一种顾虑&#xff1a; 员工到底有没有认真工作&#xff0c;工作是不是做到了全身心投入。 为什么会有担心员工工作状态的问题发生&#xff1f; 无疑是员工在上班时间浏览与工作无关的网站、下载私人文件、甚至是泄露公司机密等行为&#xff0c;让老板不放心了…

Elasticsearch:在本地使用 Gemma LLM 对私人数据进行问答

在本笔记本中&#xff0c;我们的目标是利用 Google 的 Gemma 模型开发 RAG 系统。 我们将使用 Elastic 的 ELSER 模型生成向量并将其存储在 Elasticsearch 中。 此外&#xff0c;我们将探索语义检索技术&#xff0c;并将最热门的搜索结果作为 Gemma 模型的上下文窗口呈现。 此外…

岭回归:优化预测的利器

在数据科学和机器学习的领域&#xff0c;构建准确、稳定的预测模型是一项至关重要的任务。岭回归作为一种强大的工具&#xff0c;被设计用来应对数据集中存在多重共线性的问题&#xff0c;并通过引入正则化来缩小预测误差。 1. 岭回归的原理&#xff1a; 岭回归是线性回归的一…

【国产】API接口管理平台的产品设计与搭建讲解

【国产接口管理平台】PhalApi Pro (π框架专业版) PhalApi Pro (发音&#xff1a;π框架专业版)&#xff0c;是一款国产企业级API接口管理平台&#xff0c;可以零代码、快速搭建API接口开发平台、接口开放平台、接口管理平台。基于PhalApi开源接口开发框架&#xff0c;通过低代…

【gpt实践】李某的AI课程值199吗

先说个人的答案&#xff1a;不值。但也不是说毫无价值&#xff0c;只是他的价值没那么高。 文末分享该课程&#xff0c;大家有兴趣可以看看&#xff0c;该课程是否有价值。 “清华博士”推出的199元的AI课程销售额竟然突破了5000万。这一数字让人惊叹&#xff0c;也引发了人们…

亚马逊、速卖通卖家如何做好测评让店铺销量稳定增长?

近期有刚入驻跨境电商的新买家咨询珑哥&#xff0c;店铺上的产品有人浏览&#xff0c;就是没有人下单&#xff0c;新店铺很正常因为很多人去购买东西&#xff0c;首先看的是评价&#xff0c;没有评价一般人不敢直接去下单。就像我们去淘宝买东西&#xff0c;都要看下评价&#…

测试用例的设计(2)

目录 1.前言 2.正交排列(正交表) 2.1什么是正交表 2.2正交表的例子 2.3正交表的两个重要性质 3.如何构造一个正交表 3.1下载工具 3.1构造前提 4.场景设计法 5.错误猜测法 1.前言 我们在前面的文章里讲了测试用例的几种设计方法,分别是等价类发,把测试例子划分成不同的类…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Web)上篇

提供具有网页显示能力的Web组件&#xff0c;ohos.web.webview提供web控制能力。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。示例效果请以真机运行为准&#xff0c;当前IDE预览器不支持。 需要权…

Java项目:基于springboot实现的OA协同办公系统(源码+数据库+毕业论文)

一、项目简介 本项目是一套基于Springbootvue实现的付费自习室系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

从零开始利用MATLAB进行FPGA设计(一):建立脉冲检测模型的Simulink模型2

目录 1.模块的总体结构 1.1从工作空间导入输入信号 1.2FIR滤波器 2.Subsystem 3.MATLAB Function 文章灵感来源于MATLAB官方免费教程&#xff1a;HDL Coder Self-Guided Tutorial 考虑到MATLAB官网的英文看着慢&#xff0c;再加上视频讲解老印浓浓的咖喱味&#xff0c;我…

【CSP】2021-12-2 序列查询新解 分段处理 用乘法代替加法减少时间复杂度(思想是离散化)

2021-12-2 序列查询新解 分段处理 用乘法代替加法减少时间复杂度&#xff08;思想是离散化&#xff09;2021-12-2 序列查询新解 分段处理 用乘法代替加法减少时间复杂度&#xff08;思想是离散化&#xff09; 2021-12-2 序列查询新解 分段处理 用乘法代替加法减少时间复杂度&am…

echarts绘制柱状图

<template><div><div>【大区数据信息】</div><div ref"target" class"w-full h-full" ></div></div> </template><script setup> import { ref, onMounted, watch} from "vue"; import *…

RC522刷卡电路设计及程序

一、RC522刷卡电路组成 基于RC522的刷卡电路如上图所示。该电路组成主要分为三部分&#xff1a; Receiving Circuit&#xff1a;接收电路&#xff0c;接收卡发送的数据。 Filtering Impedence-Transtorm circuit:滤波和阻抗变换电路&#xff0c;抑制高次谐波并优化到读卡器天线…

手把手写深度学习(23):视频扩散模型之Video DataLoader

手把手写深度学习(0)&#xff1a;专栏文章导航 前言&#xff1a;训练自己的视频扩散模型的第一步就是准备数据集&#xff0c;而且这个数据集是text-video或者image-video的多模态数据集&#xff0c;这篇博客手把手教读者如何写一个这样扩散模型的的Video DataLoader。 目录 准…

【Vue3】深入理解Vue3路由器的工作原理to的两种写法

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

Realsense 相机SDK学习(一)——librealsense使用方法及bug解决(不使用Ros)

一.介绍 realsense相机是一个intel开发出来的一款深度相机&#xff0c;我之前使用他来跑过slam&#xff0c;也配置过他的驱动&#xff0c;在此附上realsense的相机驱动安装方法&#xff1a;Ubuntu20.04安装Intelrealsense相机驱动&#xff08;涉及Linux内核降级&#xff09; …

【四】【算法分析与设计】贪心算法的初见

455. 分发饼干 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块饼干 j&#xff0c;都有…

AI时代Python金融大数据分析实战:ChatGPT让金融大数据分析插上翅膀【文末送书-38】

文章目录 Python驱动的金融智能&#xff1a;数据分析、交易策略与风险管理Python在金融数据分析中的应用 实战案例&#xff1a;基于ChatGPT的金融事件预测AI时代Python金融大数据分析实战&#xff1a;ChatGPT让金融大数据分析插上翅膀【文末送书-38】 Python驱动的金融智能&…

eVTOL适航领先新构型,沃飞长空布局空中交通新局面

汽车、火车、飞机……人类对于出行方式的探索从未停止。随着沃飞长空旗下首款自研eVTOL(飞行汽车)AE200适航技术验证机一阶段顺利试飞,eVTOL(飞行汽车)这种面向空中交通的新型交通工具进入了我们的视野,那么eVTOL(飞行汽车)是什么?eVTOL(飞行汽车)前景怎么样? eVTOL(飞行汽车…