vector的底层实现与模拟

在这里插入图片描述

嗨喽大家好,时隔许久阿鑫又给大家带来了新的博客,关于vector的模拟实现,下面让我们开始今天的学习吧!

vector的底层实现与模拟

1.关于vector中的插入和删除

2. vector中的拷贝构造和赋值

3.vector的构造函数

4.关于vector中浅拷贝的问题

1.关于vector中的插入和删除

typedef T* iterator;
typedef const T* const_iterator;iterator begin()
{return _start;
}
iterator end()
{return _finish;
}
const_iterator begin()const
{return _start;
}const_iterator end()const
{return _finish;
}
size_t capacity()const
{return _end_of_storage - _start;
}size_t size()const
{return _finish - _start;
}void push_back(const T& x)
{/*if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;_finish++;*/insert(_finish, x);
}T& operator[](size_t i)
{assert(i < size());return _start[i];
}void pop_back()
{_finish--;
}iterator insert(iterator pos, const T& x)
{//扩容会导致迭代器失效assert(pos >= _start);assert(pos <= _finish);int len = pos - _start;if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *(end);end--;}*pos = x;_finish++;return pos;
}void erase(iterator pos)
{//erase也会导致迭代器失效vassert(pos >= _start);assert(pos < _finish);iterator end = pos;while (end <= _finish-2){*(end ) = *(end + 1);++end;}_finish--;
}

1.1 尾插和插入时,若需要扩容应该提前保存oldsize的值

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

在这里插入图片描述

我们需要注意的是:size()返回的是_finish-_start的值,但是_start的地址再扩容后已经发生了变化,所以我们需要用oldsize记录下扩容前的对象个数,从而避免调用size()

1.2 关于erase和insert中迭代器失效的问题

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

在这里插入图片描述

有些同学想通过传引用的方法,防止外面的实参迭代器失效
注意:若采用传引用的话,由于v1.begin()是传值返回,需要调用拷贝构造,临时对象具有常性,所以pos就不能修改,所以无法完成insert成员函数的内部操作,所以不能利用传引用

在这里插入图片描述

string的插入也存在迭代器失效的场景,但大多数时候,string的插入是采用下标,所以平时不太研究string的迭代器失效的场景

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

在vs下,访问erase后失效的迭代器会直接崩溃,而在Linux下不会直接崩溃

2. vector中的拷贝构造和赋值

//强制编译器生成默认的
vector() = default;//v1(v3)
vector(const vector<T>& v){reserve(v.capacity());for (auto e:v){push_back(e);}
}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)
{//v3 = v1(this是v3的指针)this->swap(v);return *this;}

3.vector的构造函数

3.1迭代器区间初始化

类模板的成员函数,也可以是函数模板----(支持任意容器的迭代器区间初始化)

//构造函数不能显示的去调用,当一个对象进行实例化的时候
// **编译器会自动调用更匹配的构造函数进行初始化**
// 类模板的成员函数
// 函数模板 -- 目的支持任意容器的迭代器区间初始化
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{while (first != last){push_back(*first);++first;}
}
void Test_15()
{vector<int> v3(10,1);v3.insert(v3.begin() + 3, 10);for (auto ch : v3){cout << ch << " ";}cout << endl;vector<int> v4(v3.begin()+3, v3.end());for (auto ch : v4){cout << ch << " ";}cout << endl;string s("hello");vector<int> v5(s.begin(), s.end());for (auto ch : v5){cout << ch << " ";}cout << endl;}

3.2 n个val初始化

vector(size_t n, const T& val = T())//匿名对象
{T* tmp = new T[n];_start =_finish =  tmp;_end_of_storage = _start + n;
/*	reserve(n);*/for (int i = 0; i < n; i++){push_back(val);}
}vector(int n, const T& val = T())//给了一个重载的版本,用来解决编译器的匹配问题
{T* tmp = new T[n];_start = _finish = tmp;_end_of_storage = _start + n;
/*	reserve(n);*/for (int i = 0; i < n; i++){push_back(val);}
}

注意:如果没有第二个重载的版本,当遇到特定情况时,就会发生非法的间接寻址,因为在调用构造时,编译器会选择更对自己口味的构造函数,如果没有重载第二个版本,那么v3的构造就会匹配迭代器区间的初始化,从而造成非法的间接寻址。

在这里插入图片描述

3.3 initializer_list的初始化

在这里插入图片描述

库系统支持的一个类型initializer_list(和iterator有些类似,都是将某些特定功能封装成一个类)
在这里插入图片描述

这个类的对象有两个指针,支持范围for

vector(initializer_list <T> il)//采用列表进行初始化
{reserve(il.size());for (auto ch : il){push_back(ch);}}

在这里插入图片描述

关于花括号的初始化

在这里插入图片描述

4.关于vector中浅拷贝的问题

//判断是否扩容
void reserve(size_t n)
{if (n > capacity()){T* tmp = new T[n];size_t oldsize = size();if (_start){/*for (int i = 0; i < size(); i++){push_back()}*///如果采用上述代码,对内置类型和值拷贝的对象没有影响for (int i = 0; i < size(); i++){tmp[i] = _start[i];//用的是string的赋值}delete[] _start;}_start = tmp;_finish = _start + oldsize;_end_of_storage = _start + n;}
}

在这里插入图片描述

我们需要注意的是,memcpy对于任意类型的拷贝都是值拷贝

好啦,今天的内容我们就学习到这里,如果大家觉得阿鑫写的不错的话,记得留下你的一键三连哦,期待我们的下一次相遇

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

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

相关文章

微信小程序报错:notifyBLECharacteristicValueChange:fail:nodescriptor的解决办法

文章目录 一、发现问题二、分析问题二、解决问题 一、发现问题 微信小程序报错&#xff1a;notifyBLECharacteristicValueChange:fail:nodescriptor 二、分析问题 这个提示有点问题&#xff0c;应该是该Characteristic的Descriptor有问题&#xff0c;而不能说nodescriptor。 …

windows docker desktop 更换镜像存储目录

windows docker desktop 更换镜像存储目录 方法&#xff1a;如图&#xff0c;Browse浏览一个新的目录并选中&#xff0c;确定后&#xff0c;程序会开始stop&#xff0c;在stop完成前&#xff0c;会持续迁移原有镜像到新的位置&#xff0c;你会发现目标位置的磁盘占用空间越来越…

DNS服务的部署与配置(1)

一、DNS的定义 1、域名系统&#xff08;英文&#xff1a;Domain Name System&#xff0c;缩写&#xff1a;DNS&#xff09;是互联网的一项服务。 它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便地访问互联网。 DNS使用UDP端口53。 当前&#xff0…

使用pygame绘制图形

参考链接&#xff1a;https://www.geeksforgeeks.org/pygame-tutorial/?reflbp 在窗口中绘制单个图形 import pygame from pygame.locals import * import sys pygame.init()window pygame.display.set_mode((600,600)) window.fill((255,255,255))# pygame.draw.rect(wind…

WSL调用docker

WSL&#xff08;windows subsystem linux&#xff09;是window系统的原生linux子系统&#xff0c;用于代码开发很方便。 希望在wsl里面运行docker&#xff0c;首先要安装docker在WSL中使用&#xff0c;大部分人的第一想法肯定是用以下命令行安装&#xff08;个人不推荐&#x…

【C语言】指针运算

前言 前面在“走进指针世界”中我已经讲解过指针相关的很多前置知识&#xff0c;其实还有一个很重要的部分就是指针的运算。这篇博客&#xff0c;就让我们一起了解一下指针的运算吧&#xff01; 指针作为变量&#xff0c;是可以进行算术运算的&#xff0c;只不过情况会和整型…

Behind the Code:Polkadot 如何重塑 Web3 未来

2024 年 5 月 17 日 Polkadot 生态 Behind the Code 第二季第一集 《创造 Web3 的未来》正式上线。第一集深入探讨了 Polkadot 和 Web3 技术在解决数字身份、数据所有权和去中心化治理方面的巨大潜力。 &#x1f50d; 查看完整视频&#xff1a; https://youtu.be/_gP-M5nUidc?…

aws glue配置读取本地kafka数据源

创建连接时填写本地私有ip地址&#xff0c;选择网络配置 配置任务选择kafka作为数据源 但是执行任务时日志显示连接失败 文档提到只能用加密通信 如果您希望与 Kafka 数据源建立安全连接&#xff0c;请选择 Require SSL connection (需要 SSL 连接)&#xff0c;并在 Kafka priv…

滑动谜题 leetcode的BFS题目 启发如何写一个拼图编程呢

题目链接 题目要求&#xff0c;要将上面的拼板拼成123450 首先&#xff0c;转换为字符串&#xff0c;为什么要转换为字符串呢&#xff0c;因为处理会变得很简单比如示例一&#xff0c;转化为字符串是12345&#xff0c;目标字符串为123450&#xff0c;只需要证明通过某种交换&a…

JDBC(Java DataBase Connectivity)Java数据库连接

JDBC(Java DataBase Connectivity) Java 语言连接数据库 再本模块中,java提供里一组用于连接数据库的类和接口Java 语言开发者,本身没有提供如何具体连接数据库的功能只是定义了一组java程序连接数据库的访问接口 连接到数据库向数据库发送增,修改,删除这一类的sql发送查询sq…

【vue echart】完成一个简单echart图表+自适应

实现效果&#xff1a; html&#xff1a; <divref"echartOne"id"echartOne"style"width: 100%; height: 100%" ></div> js: getEchartOne() {let chart this.$echarts.init(this.$refs.echartOne);chart.setOption({title: {text:…

vue 纵向滚动菜单, 点击滚动到选中菜单

1 背景 需要设计一个纵向滚动菜单&#xff0c;要求丝滑点&#xff0c;默认显示选中菜单 2 思路 给定一个容器&#xff0c;样式包含overflow:hidden&#xff0c;默认高宽足够显示一个菜单&#xff08;以下用图标代替菜单&#xff09;&#xff0c;鼠标悬浮时增大容器高度&#…

揭秘Python的魔法:装饰器的超能力大揭秘 ‍♂️✨

文章目录 Python进阶之装饰器详解1. 引言装饰器的概念与意义装饰器在Python编程中的作用 2. 背景介绍2.1 函数作为对象2.2 高阶函数 3. 装饰器基础3.1 理解装饰器3.2 装饰器的工作原理 4. 带参数的装饰器4.1 为什么需要带参数4.2 实现带参数的装饰器使用函数包裹装饰器使用类实…

通过el-tree自定义渲染网页版工作目录,实现鼠标悬浮显示完整名称、用icon区分文件和文件夹等需求

目录 一、通过el-tree自定义渲染网页版工作目录 1.1、需求介绍 1.2、使用el-tree生成文档目录 1.2.1、官方基础用法 ①效果 ②代码&#xff1a; 1.2.2、自定义文档目录&#xff08;实现鼠标悬浮显示完整名称、用icon区分文件和文件夹&#xff09; ①效果&#xff08;直接效…

语义化版本规范

Releases 是指软件或项目的正式发布版本&#xff0c;在浏览一些开源仓库时&#xff0c;可以看到当前项目最新版本和历史版本 仔细研究就会发现&#xff0c;版本号不是以固定值递增的&#xff0c;有时候第三位加 1&#xff0c;有时候加 2&#xff0c;有时候直接把第一位加 1&…

BUUCTF---web---[BJDCTF2020]ZJCTF,不过如此

1、点开连接&#xff0c;页面出现了提示 传入一个参数text&#xff0c;里面的内容要包括I have a dream。 构造&#xff1a;?/textI have a dream。发现页面没有显示。这里推测可能得使用伪协议 在文件包含那一行&#xff0c;我们看到了next.php的提示&#xff0c;我们尝试读取…

Blender导出fbx模型,导入到ue5中模型丢失纹理材质

UE5系列文章目录 文章目录 UE5系列文章目录前言一、问题原因二、最终效果 前言 Blender导出fbx模型&#xff0c;导入到ue5中&#xff0c;发现模型丢失纹理材质&#xff0c;里面的原神人物模型妮露居然是白模&#xff0c;郁闷了大半天 一、问题原因 我在Blender导出fbx文件时…

JVM类加载

文章目录 类加载1.类的生命周期加载阶段连接阶段初始化阶段 2.类加载器类加载器的分类启动类加载器(Bootstarp)扩展类加载器&应用程序加载器 3.类的双亲委派机制什么是双亲委派机制&#xff1f;打破双亲委派机制自定义类加载器线程上下文类加载器 类加载 注&#xff1a;本…

Springboot+Vue项目-基于Java+MySQL的酒店管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…