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

【C++】vector介绍以及模拟实现(超级详细<=>源码并存)

欢迎来到我的Blog,点击关注哦💕

【C++】vector介绍以及模拟实现

  • 前言
    • vector介绍
  • vector常见操作
    • 构造函数
    • iterator
    • capacity
    • modify
  • `vector`模拟实现
    • 存储结构
    • 默认构造函数
    • 构造函数
      • 拷贝构造函数
      • 赋值运算符重载
      • 析构函数
    • 容量(capacity)
      • `size`和`capzcity`
      • reserve
      • resize
    • 修改(modify)
      • push_back
            • 直接将`_finsih`位置解引用赋值,`++_finsih`
      • pop_back
      • insert
      • erase
    • 元素访问(Element access)
      • operator [ ]
    • 迭代器(iterator)
  • 源码

前言

string的特性和用法以及底层的探索已经,虽然string不算container的成员之一,但是也见到了其的影子,接下来让我们看看vector

vector介绍

vector 是 C++ 标准模板库(STL)中的一个动态数组容器,它提供了动态大小调整和高效的随机访问功能。vector 的元素在内存中是连续存储的,这意味着可以通过指针或索引高效地访问元素。vector 自动管理其内部使用的内存,不需要手动分配和释放,支持常见容器操作,如插入、删除、遍历等.

vector常见操作

构造函数

(constructor)构造函数声明接口说明
vector(size_type n, const value_type& val = value_type())构造并初始化n个val
vector (const vector& x); (重点)拷贝构造
vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造

iterator

函数声明接口说明
begin + end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin + rend返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的 reverse_iterator,即begin位置

capacity

函数声明接口说明
capacity获取容量大小
sizesize 获取数据个数
empty判断是否为空
resize改变vector的size
reserve改变vector的capacity

modify

vector增删查改接口说明
push_back(重点)尾插
pop_back (重点)尾删
find查找。(注意这个是算法模块实现,不是vector的成员接口)
insert在position之前插入val
erase删除position位置的数据
swap交换两个vector的数据空间
operator[]像数组一样访问

vector模拟实现

存储结构

结构上使用命名空间myvector进行封装,防止与库冲突,使用class封装成为对象vector

这样typedef的一点是和STL保持一致

  • vector写成类模板,可以支持存贮多种类型数据
  • _start表示数据存储的开始地址
  • _finish表示数据存贮的的下一个地址
  • _end_of_storage表示数据当前开辟的最大空间的地址
namespace myvector
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;private:iterator _start;iterator _finish;iterator _end_of_storage;};
}

默认构造函数

构造函数

  • 初始化是使用的都是空指针
vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}
  • 使用nval初始化对象
vector(size_t n, const T& val = T())
{
resize(n, val);
}
  • 根据可以模板的嵌套的性质,再次进行模板的定义
  • 这是使用两个迭代器的进行初始化
template<class InputIterator>vector(InputIterator first, InputIterator last)
{while (first != last){push_back(*first);++first;}
}

拷贝构造函数

  • 利用一个对象初始化另外一个对象传引用
  • new出和传递的对象一样大小的空间,在string类中我们利用了mencpy进行拷贝,在vector中不采用mencpy
    1. mencpy拷贝只能进行内置类型的浅拷贝,不能进行自定义类型的深拷贝
    2. 在这里面进行依次赋值,或者push_back
  • 最后进行_finish_end_of_storage的初始化
vector(const vector<T>& v)
{_start = new T[v.capacity()];for (size_t i = 0; i < v.size(); i++){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();}

赋值运算符重载

  • operator=的参数中是值传递,是实参的拷贝,这里面利用这个特性进数据的交换
  • 返回this指针就是赋值的内容了
void swap(vector<T> v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);
}vector<T> operator=(vector<T> v)
{swap(v);return *this;
}

析构函数

  • 判断_start是否为空为空,避免再次析构
~vector()
{if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}

容量(capacity)

sizecapzcity

  • vectorsizecapacity不同于string类中的不一样,vector定义的是指针
  • 充分利用只针的特性,(指针—指针)是数值,可以计算出capacitysize
size_t size()const 
{
return _finish - _start;
}
size_t capacity()const 
{
return _end_of_storage - _start;
}

reserve

  • 开始判断需要扩容的大小是否大于capacity,以避免重复扩容效率低下
  • 在开始时候记录原始空间的大小,是为了避免迭代器失效
    1. 进行空间的扩容,会将原来的空间析构,原始的计算空间大小已经已释放,指向的_start _finish _end_of_storage已经失效
  • 这里还是采用在这里面进行依次赋值,或者push_back
  • 更新_start _finish _end_of_storage
void reserve(size_t n)
{if (n > capacity()){T* tmp = new T[n];size_t sz = size();if (_start){//memcpy(tmp, _start, sizeof(T)*capacity());//string 类深拷贝for (int i = 0; i < sz; i++){tmp [i] = _start[i];}delete[] _start;}_start = tmp;_finish = sz + _start;_end_of_storage = _start + n;}
}

resize

  • 两种情况

    1. N<capacity

      直接进行移动_finish

    2. N>capacity

      进行容量的检查和扩容,依次赋值val

  • const T& val = T()这句话是针对内置类型和自定义类型,C++这里将内置类型进行了升级

    int = 1; <=> int(1);//这里int有点像构造函数
    
void resize(size_t n, const T& val = T())
{if (n < capacity()){_finish = n + _start;}else{reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}
}

修改(modify)

push_back

  • 首先进行容量的检查

  • 直接将_finsih位置解引用赋值,++_finsih
void push_back(const T& x)
{if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;++_finish;
}

pop_back

  • 复用erase
void pop_back()
{
erase(end()-1);
}

insert

  • 进行断言,防止pos越界访问
  • 判断空间的大小_finish == _end_of_storage
  • size_t step = pos - _startstep记录,距离 _start距离,扩容的时候将原空间释放,pos将无法访问,扩容完成后进行pos的恢复
  • pos位置的数据依次进行移动、
  • 插入pos位置的值,修改_finish
  • 为了避免迭代器失效,返回现在的位置pos
iterator insert(iterator pos, const T& x)
{assert(pos <= _finish && pos >= _start);if (_finish == _end_of_storage){//防止迭代器失效size_t step = pos - _start;size_t newcapacity = capacity() == 0 ? 0 : capacity() * 2;reserve(newcapacity);//防止迭代器失效pos = _start + step;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;++end;}*pos = x;++_finish;return pos
}

erase

  • 进行断言,防止pos越界访问
  • pos后面的元素向前面移动,进行覆盖
  • 为了避免迭代器失效,返回现在的位置pos
iterator erase(iterator pos)
{assert(pos <= _finish && pos >= _start);while (pos != _finish){*pos = *(pos + 1);pos++;}--_finish;return pos
}

元素访问(Element access)

operator [ ]

  • 实现const非const两种,只读和可读可改
  • 充分利用字符串特性可以进行下标的访问
T& operator[](size_t pos)
{assert(pos >= 0 && pos < size());return _start[pos];
}const T& operator[](size_t pos)const
{assert(pos >= 0 && pos < size());return _start[pos];
}

迭代器(iterator)

  • 本质还是指针,直接进行指针的返回就好
//iterator
const_iterator cbegin()
{return _finish;
}const_iterator cend() const
{return _start;
}
iterator begin()
{return _start;
}
iterator end()
{return _finish;
}
const_iterator begin()const
{return _start;
}
const_iterator end()const
{return _finish;

源码

#include <string.h>
#include <assert.h>
#include <iostream>namespace MyVector
{template <class T>class vector{public://iteratorconst_iterator cbegin(){return _finish;}const_iterator cend() const{return _start;}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin()const{return _start;}const_iterator end()const{return _finish;}//默认构造vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}vector(size_t n, const T& val = T()){resize(n, val);}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}vector(const vector<T>& v){_start = new T[v.capacity()];for (size_t i = 0; i < v.size(); i++){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();}void swap(vector<T> v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector<T> operator=(vector<T> v){swap(v);return *this;}//capacityvoid reserve(size_t n){if (n > capacity()){std::cout << "reserve(size_t n)" << std::endl;T* tmp = new T[n];size_t sz = size();if (_start){//memcpy(tmp, _start, sizeof(T)*capacity());//string 类深拷贝for (int i = 0; i < sz; i++){tmp [i] = _start[i];}delete[] _start;}_start = tmp;_finish = sz + _start;_end_of_storage = _start + n;}}size_t size(){return _finish - _start;}size_t capacity(){return _end_of_storage - _start;}size_t size()const {return _finish - _start;}size_t capacity()const {return _end_of_storage - _start;}//modifyvoid push_back(const T& x){if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;++_finish;}void pop_back(){erase(end()-1);}void insert(iterator pos, const T& x){assert(pos <= _finish && pos >= _start);if (_finish == _end_of_storage){//防止迭代器失效size_t step = pos - _start;size_t newcapacity = capacity() == 0 ? 0 : capacity() * 2;reserve(newcapacity);//防止迭代器失效pos = _start + step;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;++end;}*pos = x;++_finish;return pos;}void erase(iterator pos){assert(pos <= _finish && pos >= _start);while (pos != _finish){*pos = *(pos + 1);pos++;}--_finish;return pos;}void resize(size_t n, const T& val = T()){if (n < capacity()){_finish = n + _start;}else{reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}}T& operator[](size_t pos){assert(pos >= 0 && pos < size());return _start[pos];}const T& operator[](size_t pos)const{assert(pos >= 0 && pos < size());return _start[pos];}private:iterator _start;iterator _finish;iterator _end_of_storage;};}

相关文章:

【C++】vector介绍以及模拟实现(超级详细<=>源码并存)

欢迎来到我的Blog&#xff0c;点击关注哦&#x1f495; 【C】vector介绍以及模拟实现 前言vector介绍 vector常见操作构造函数iteratorcapacitymodify vector模拟实现存储结构默认构造函数构造函数拷贝构造函数赋值运算符重载析构函数 容量&#xff08;capacity&#xff09;si…...

【Redis 进阶】主从复制(重点理解流程和原理)

在分布式系统中为了解决单点问题&#xff08;某个服务器程序只有一个节点&#xff08;只搞一个物理服务器来部署这个服务器程序&#xff09;。可用性不高&#xff1a;如果这个机器挂了意味着服务就中断了&#xff1b;性能 / 支持的并发量比较有限&#xff09;。通常会把数据复制…...

Git常用命

转自&#xff1a;https://blog.csdn.net/ahjxhy2010/article/details/80047553 1.查看某个文件或目录的修改历史 git log filename #查看fileName相关的commit记录 git log -p filenam # 显示每次提交的diff#只看某次提交中的某个文件变化&#xff0c;commit-id  文件名…...

强化学习时序差分算法之Q-learning算法——以悬崖漫步环境为例

0.简介 基于时序差分算法的强化学习算法除了Sarsa算法以外还有一种著名算法为Q-learning算法&#xff0c;为离线策略算法&#xff0c;与在线策略算法Sarsa算法相比&#xff0c;其时序差分更新方式变为 Q(St,At)←Q(St,At)α[Rt1γmaxaQ(St1,a)−Q(St,At)] 对于 Sarsa 来说&am…...

111推流111

推流推流...

刷题——数组中只出现一次的两个数字

数组中只出现一次的两个数字_牛客题霸_牛客网 描述 一个整型数组里除了两个数字只出现一次&#xff0c;其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 数据范围&#xff1a;数组长度 2≤n≤10002≤n≤1000&#xff0c;数组中每个数的大小 0<val≤100000…...

《剖析程序员面试“八股文”:助力、阻力还是噱头?》

#“八股文”在实际工作中是助力、阻力还是空谈&#xff1f; 作为现在各类大中小企业面试程序员时的必问内容&#xff0c;“八股文”似乎是很重要的存在。但“八股文”是否能在实际工作中发挥它“敲门砖”应有的作用呢&#xff1f;有IT人士不禁发出疑问&#xff1a;程序员面试考…...

Redis过期key的删除策略

在 Redis 中&#xff0c;设置了过期时间的键在过期时间到达后&#xff0c;并不会立即从内存中删除。如果不是&#xff0c;那过期后到底什么时候被删除呢&#xff1f; 下面对这三种删除策略进行具体分析。 立即删除&#xff1a; 立即删除能够保证内存数据的及时性和空间的有效…...

软件管理

设备挂载在目录下才可以读 挂载类似于将u盘插在电脑上 mount /dev/sr0 /opt/openeuler/ vim /etc/rc.d/rc.local #开机自运行脚本&#xff0c;将挂载命令写入脚本&#xff0c;并给这个脚本执行权限 chmod x /etc/rc.d/rc.local [rootlocalhost ~]# cd /etc/yum.repos.d/ […...

【2024】Datawhale AI夏令营 Task3笔记——Baseline2部分代码解读及初步上分思路

【2024】Datawhale AI夏令营 Task3笔记——Baseline2部分代码解读及初步上分思路 本文对可完成赛事“逻辑推理赛道&#xff1a;复杂推理能力评估”初赛的Baseline2部分关键代码进行详细解读&#xff0c;介绍Baseline2涉及的关键技术和初步上分思路。 Baseline2代码由Datawhal…...

软件测试——测试分类(超超超齐全版)

为什么要对软件测试进行分类 软件测试是软件⽣命周期中的⼀个重要环节&#xff0c;具有较⾼的复杂性&#xff0c;对于软件测试&#xff0c;可以从不同的⻆度加以分类&#xff0c;使开发者在软件开发过程中的不同层次、不同阶段对测试⼯作进⾏更好的执⾏和管理测试的分类⽅法。…...

深入解析 Go 语言 GMP 模型:并发编程的核心机制

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff1a;点击跳转到网站&#xff0c;对人工智能感兴趣的小伙伴可以点进去看看。 前言 本章是Go并发编程的起始篇章&#xff0c;在未来几篇文章中我们会…...

PHP中如何处理字符串

在PHP中&#xff0c;处理字符串是一项非常常见的任务&#xff0c;PHP提供了大量的内置函数来方便地处理字符串。以下是一些常用的字符串处理函数&#xff1a; strlen() - 返回字符串的长度。 php复制代码 $text "Hello, World!"; echo strlen($text); // 输出&…...

windows内存泄漏检查汇总

VLD(Visual Leak Detector) 下载 官方下载地址2.5 另一分支2.7 安装 点击运行安装...

yolo格式数据集之空中及地面拍摄道路病害检测7种数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用

yolo格式数据集之空中及地面拍摄道路病害检测7种数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用 本数据为空中及地面拍摄道路病害检测检测数据集&#xff0c;数据集数量如下&#xff1a; 总共有:33585张 训练集&#xff1a;6798张 验证集&#xff1a;3284张 测试集&a…...

[Meachines] [Easy] Mirai Raspberry树莓派默认用户登录+USB挂载文件读取

信息收集 IP AddressOpening Ports10.10.10.48TCP:22,53,80,1276,32400,32469 $ nmap -p- 10.10.10.48 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 6.7p1 Debian 5deb8u3 (protocol 2.0) | ssh-hostkey: | 1024 aa:ef:5c:…...

从零开始安装Jupyter Notebook和Jupyter Lab图文教程

前言 随着人工智能热浪&#xff08;机器学习、深度学习、卷积神经网络、强化学习、AGC以及大语言模型LLM, 真的是一浪又一浪&#xff09;的兴起&#xff0c;小伙伴们Python学习的热情达到了空前的高度。当我20年前接触Python的时候&#xff0c;做梦也没有想到Python会发展得怎么…...

数据库魔法:SQL Server中自定义分区函数的奥秘

数据库魔法&#xff1a;SQL Server中自定义分区函数的奥秘 在SQL Server中&#xff0c;分区表是管理大型表和提高查询性能的强大工具。分区函数和分区方案允许你根据特定的规则将数据分散到不同的文件组中。本文将深入探讨如何在SQL Server中实现数据库的自定义分区函数&#…...

网页禁止移除水印

一般的话水印分为明水印和暗水印两种 明水印的话就是在视频canvas上面蒙上一个div&#xff08;如我上篇文章&#xff09; &#xff0c;暗水印的话就是把文字通过技术嵌入到图像里。 具体实现的话可以使用MutationObserver API 来监视 DOM 的变化&#xff0c;特别是针对目标节…...

Node Red 与axios简易测试环境的搭建

为了学习在vue3中如何使用axios&#xff0c;我借Sider Fusion的帮助搭建了基于node的简易测试环境。 Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;通常用于浏览器环境&#xff0c;但它也可以在 Node.js 环境中使用。因此&#xff0c;可以在 Ubuntu 的 Bash 环境下通过…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

Golang dig框架与GraphQL的完美结合

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

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...