std::vector的模拟实现

目录

构造函数

无参构造

用n个val来初始化的拷贝构造

拷贝构造

用迭代器初始化

析构函数

reserve

resize

pushback

pop_back

迭代器及解引用

迭代器的实现

解引用[ ]

insert

erase

赋值拷贝

补充


vector底层也是顺序表,但是vector可以储存不同的类型包括自定义类型和内置类型,所以在实现vector的时候要用模板实现。vector的成员变量与string是不同的,vector的成员变量是3个迭代器,分别是指向顺序表起始位置的指针,指向最后一个数据下一个位置的指针以及指向尾部开辟的空间。

namespace cfl
{template<class T>class vector{typedef T* iterator;public:private:iterator _start;      //指向顺序表的开头iterator _finish;     //指向顺序表最后一个有效数据的下一个位置iterator _end_of_storage;	//指向最后一个开辟的空间的下一个位置};
}

构造函数

vector的构造函数有5个,我们先实现4个,有一个涉及到容器分配器在写容器篇博客时会实现。

无参构造

//无参构造
vector():_start(nullptr),_finish(nullptr),_end_of_storage(nullptr)
{}

用n个val来初始化的拷贝构造
 

//用n个val来初始化的拷贝构造
vector(size_t n, const T& val)
{_start = new T[n];for (int i = 0; i < n; i++)_start[i] = val;_finish = _start + n;_end_of_storage = _start + n;
}

拷贝构造

注意在进行拷贝构造的时候,不建议使用memcpy,因为在使用memcpy的时候内置类型不会出问题,但是对于自定义类型可能会出现浅拷贝,自定义类型中有指针就只是简单的拷贝其地址,导致两个vector指向同一块位置,就会调用两次析构函数。

size_t size()const
{return _finish - _start;
}size_t capacity()const
{return _end_of_storage - _start;
}//拷贝构造
vector(const vector& v)
{_start = new T[v.capacity()];//memcpy(_start, v._start, v.size()*sizeof(T));用memcpy,如果T是自定义类型可能会导致浅拷贝比如T是string,则指挥拷贝string的地址,导致两个vector指向一个位置//用for循环和赋值运算符重载来实现for (int i = 0; i < v.size(); i++){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();
}

用迭代器初始化

 此处使用迭代器初始化为了方便直接调用push_back(在后面实现)。

//用迭代器初始化
template<class InputIterator>  //此处用一个函数迭代器,使得vector可以用各种类型初始化,能用int数组也能用string等
vector(InputIterator first, InputIterator last)
{//直接调用push_back让其去开辟空间while (first != last){push_back(*first);++first;}
}

析构函数

~vector()
{delete[] _start;_start = _finish = _end_of_storage = nullptr;
}

reserve

用reserve进行空间的开辟,与拷贝构造同理,这里也不建议使用memcpy进行拷贝。

void reserve(size_t n)
{if (n > capacity()){iterator tmp = new T[n];int sz = size();for (int i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}
}

resize

resize传参时如果小于size(),就会对空间进行缩小,如果大于就会额外对额外的空间进行初始化。

void resize(size_t n,const T& val=T()) //如果没有传val就用编译器默认的初始化
{if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish != _end_of_storage){*(_finish) = val;++_finish;}}
}

pushback

void push_back(const T& val)
{if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : 2 * capacity());}*(_finish) = val;++_finish;
}

pop_back

尾删。

void pop_back()
{_finish--;
}

迭代器及解引用

迭代器的实现

对于迭代器的实现就是实现begin和end。

迭代器的实现也分为两种:非const版本和const版本。

iterator begin()
{return _start;
}
iterator end()
{return _finish;
}typedef const T* const_iterator;
const_iterator begin()const
{return _start;
}
const_iterator end()const
{return _finish;
}

解引用[ ]

//解引用运算符重载
T& operator[](size_t pos)
{assert(pos < size());return _start[pos];
}

insert

insert插入。insert传的pos是在_start和_finish之间的,所以在扩容后对导致_start指向新的空间了,但是pos位置还指向原位置,所以扩容后要对pos位置进行更新。

void insert(iterator pos, const T& val)
{assert(pos < _finish);if (_finish == _end_of_storage){int num = pos - _start;  //如果想开辟空间,会导致_start指向新的位置但是pos还指向原处reserve(2 * capacity());pos = _start + num; //对pos位置进行更新}iterator end = _finish;while (end > pos){*(end) = *(end - 1);--end;}*pos = val;++_finish;
}

insert后不能再使用pos这个迭代器了,因为他可能失效。 可以用一个返回值来返回新的pos位置。


erase

指定位置删除。

void erase(iterator pos)
{iterator cur = pos;while (cur + 1 < _finish){*(cur) = *(cur + 1);++cur;}--_finish;
}

赋值拷贝

void swap(T& tmp)
{swap(this->_start, tmp._start);swap(this->_finish, tmp._finish);swap(this->_end_of_storage, tmp._end_of_storage);
}//赋值拷贝
T& operator=(T tmp)
{swap(tmp);
}

此处赋值拷贝还是使用交换临时变量的方法,即能够将tmp拷贝构造的空间给this还能让tmp去销毁this的原本数据。


补充

一些vector不常用的成员函数。

1)rbegin,rend从后往前开始;

2)clear()清除vector中的数据,不清除空间;

3)vector<vector<T>>实现用vector模拟二维数组。

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

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

相关文章

蓝桥杯刷题周计划(第二周)

目录 前言题目一题目代码题解分析 题目二题目代码题解分析 题目三题目代码题解分析 题目四题目代码题解分析 题目五题目代码题解分析 题目六题目代码题解分析 题目七题目代码题解分析 题目八题目题解分析 题目九题目代码题解分析 题目十题目代码题解分析 题目十一题目代码题解分…

clion+arm-cm3+MSYS-mingw +jlink配置用于嵌入式开发

0.前言 正文可以跳过这段 初识clion&#xff0c;应该是2015年首次发布的时候&#xff0c; 那会还是大三&#xff0c;被一则推介广告吸引到&#xff0c;当时还在用vs studio&#xff0c;但是就喜欢鼓捣新工具&#xff0c;然后下载安装试用了clion&#xff0c;但是当时对cmake规…

蓝桥杯备考:离散化详解

首先&#xff0c;为什么要有离散化呢&#xff1f; 比如这道题&#xff0c;我们应该开一个差分数组&#xff0c;但是a&#xff0c;b之间的间隔可是太大了&#xff0c;难道我们要开一个2的三十二次方大小的数组吗&#xff1f;我们也是开不了这么大的数组的 我们就需要把这些数离…

初学者快速入门Python爬虫 (无废话版)

全篇大概 5000 字(含代码)&#xff0c;建议阅读时间 40min 一、Python爬虫简介 1.1 什么是网络爬虫&#xff1f; 定义&#xff1a; 网络爬虫&#xff08;Web Crawler&#xff09;是自动浏览互联网并采集数据的程序&#xff0c;就像电子蜘蛛在网页间"爬行"。 分类&…

Day05 实例:正向反向连接内外网环境防火墙出入站

一、正反向连接 0、先将防火墙关闭 Linux&#xff1a; sudo systemctl stop firewalld Windows&#xff1a;netsh advfirewall set allprofiles state off 1、正向连接 1.1 Linux连接Windows 00x1 开启两台服务器 并且给Windows拖入nc.exe 00x2 Windows绑定自己5566端…

电力系统中各参数的详细解释【智能电表】

一、核心电力参数 电压 (Voltage) 单位&#xff1a;伏特&#xff08;V&#xff09; 含义&#xff1a;电势差&#xff0c;推动电流流动的动力 类型&#xff1a;线电压&#xff08;三相系统&#xff09;、相电压&#xff0c;如220V&#xff08;家用&#xff09;或380V&#xff…

【仿muduo库one thread one loop式并发服务器实现】

文章目录 一、项目介绍1-1、项目总体简介1-2、项目开发环境1-3、项目核心技术1-4、项目开发流程1-5、项目如何使用 二、框架设计2-1、功能模块划分2-1-1、SERVER模块2-1-2、协议模块 2-2、项目蓝图2-2-1、整体图2-2-2、模块关系图2-2-2-1、Connection 模块关系图2-2-2-2、Accep…

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_cycle_modules

声明在 src/core/ngx_module.h ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle);实现在 src/core/ngx_module.c ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle) {/** create a list of modules to be used for this cycle,* copy static modules to it*/cycle->modul…

Vue3实战学习(IDEA中打开、启动与搭建Vue3工程极简脚手架教程(2025超详细教程)、Windows系统命令行启动Vue3工程)(2)

目录 一、命令行中重新启动已搭建好的Vue3工程。(快速上手) &#xff08;0&#xff09;Windows环境下使用命令行从零到一手动搭建Vue3工程教程。 &#xff08;1&#xff09;首先找到已建Vue3工程的目录。 &#xff08;2&#xff09;无需再下载依赖包&#xff0c;直接执行npm ru…

使用websocket,注入依赖service的bean为null

问题&#xff1a;依赖注入失败&#xff0c;service获取不到&#xff0c;提示null 这是参考代码 package com.shier.ws;import cn.hutool.core.date.DateUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.google.gson.Gson; import com.s…

《A++ 敏捷开发》- 18 软件需求

需求并不是关于需求 (Requirements are not really about requirements) 大家去公共图书馆寄存物品&#xff0c;以前都是扫二维码开箱&#xff0c;有些图书馆升级了使用指纹识别。 “是否新方法比以前好&#xff1f;”我问年轻的开发人员。 “当然用指纹识别好。新技术&#x…

基于AMD AU15P FPGA的SLVS-EC桥PCIe设计方案分享

作者&#xff1a;Hello,Panda 各位FPGAer周末愉快&#xff0c;今天熊猫君分享一个基于AMD AU15P FPGA的SLVS-EC桥PCIe设计方案。 一、方案背景 先说方案的应用背景&#xff1a;众所周知&#xff0c;较为上层的如基于AI的机器视觉应用&#xff0c;大多基于高端的专用SoC、AI专…

Redis|Springboot集成Redis

文章目录 总体概述本地Java连接Redis常见问题集成Jedis集成lettuce集成RedisTemplate——推荐使用连接单机连接集群 总体概述 jedis-lettuce-RedisTemplate三者的联系 jedis第一代lettuce承上启下redistemplate着重使用 本地Java连接Redis常见问题 bind配置请注释掉保护模式…

机器学习(六)

一&#xff0c;决策树&#xff1a; 简介&#xff1a; 决策树是一种通过构建类似树状的结构&#xff08;颠倒的树&#xff09;&#xff0c;从根节点开始逐步对数据进行划分&#xff0c;最终在叶子节点做出预测结果的模型。 结构组成&#xff1a; 根节点&#xff1a;初始的数据集…

恢复IDEA的Load Maven Changes按钮

写代码的时候不知道点到什么东西了&#xff0c;pom文件上的这个弹窗就是不出来了&#xff0c;重启IDEA&#xff0c;reset windos都没用&#xff0c;网上搜也没收到解决方案 然后开打开其他项目窗口时&#xff0c;看到那个的功能名叫 Hide This Notification 于是跑到Setting里…

怎么使用Sam Helper修改手机屏幕分辨率,使得游戏视野变广?

1.准备Shizuku 和Sam Helper软件 2.打开设置&#xff0c;找到关于本机&#xff0c;连续点击版本号五次打开开发者选项 3.找到开发者选项&#xff0c;打开USB调试和无线调试 4.返回桌面&#xff0c;我们接着打开shizuku,点击配对&#xff0c;这里打开开发者选项&#xff0c;找…

【招聘精英】

我们公司是一个位于石家庄的一个科技型新型技术公司。主要做人力资源、用工、科技等方面。 有意向回石家庄的或者已经在石家庄的技术大咖、软件大牛、产品大佬、UI大神可以来了解一下。 现在招聘 高级前端开发 高级java开发 其他岗位也可以联系。 有意向的朋友可以私信我。 -…

大模型信息整理

1. Benchmarks Reasoning, conversation, Q&A benchmarks HellaSwagBIG-Bench HardSQuADIFEvalMuSRMMLU-PROMT-BenchDomain-specific benchmarks GPQAMedQAPubMedQAMath benchmarks GSM8KMATHMathEvalSecurity-related benchmarks PyRITPurple Llama CyberSecEval2. 国内外…

Redis-限流方案

在实际业务中&#xff0c;可能会遇到瞬时流量剧增的情况&#xff0c;大量的请求可能会导致服务器过载和宕机。为了保护系统自身和上下游服务&#xff0c;需要采用限流的方式&#xff0c;拒绝部分请求。 限流就是对请求的频率进行控制&#xff0c;迅速拒绝超过请求阈值的请求。 …

无感方波开环强拖总结

一、强拖阶段的核心原理与设计要点 开环换相逻辑 固定频率斜坡&#xff1a;以预设斜率逐步提升换相频率&#xff08;如0.5-5Hz/ms&#xff09;&#xff0c;强制电机跟随磁场旋转。电压-频率协调控制&#xff1a;初始阶段施加高电压&#xff08;80%-100%额定&#xff09;克服静摩…