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

C++vector常用接口和模拟实现

C++中的vector是一个可变容量的数组容器,它可以像数组一样使用[]进行数据的访问,但是又不像C语言数组空间是静态的,它的空间是动态可变的。

在日常中我们只需要了解常用的接口即可,不常用的接口查文档即可。

1.构造函数

//空构造
vector()//拷贝构造
vector(const vector<T>& v)//构造并初始化n个val
vector(size_t n,const T& val = T())//使用迭代器初始化,这里写成模板
template<class InputIterator>
vector(InputIterator first, InputIterator last)

2.迭代器

对于vector的迭代器也可以看作是指针

//获取第一个位置数据的普通迭代器和const迭代器
iterator begin();
const_iterator begin() const;//获取最后一个位置数据的普通迭代器和const迭代器
iterator end();
const_iterator end() const;

3.空间管理

//获取元素个数
size_t size() const;//判断是否为空
bool empty() const;//改变大小并且初始化
void resize (size_type n, value_type val = value_type());//改变容量
void reserve (size_type n);

reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问 题。 resize在开空间的同时还会进行初始化,影响size。

4.增删改查

//尾插
void push_back (const value_type& val);//尾删
void pop_back();//在任意位置插入
iterator insert (iterator position, const value_type& val);//在任意位置删除
iterator erase (iterator position);//交换两组数据空间
void swap (vector& x);//[]重载
T& operator[](size_t pos)

这里需要了解一个问题就是迭代器失效的问题,对于vector而言,它的迭代器底层就是原生指针。因此迭代器失效的原因就是指针所指向的空间被销毁了,指向了一个已经被释放的空间。

    vector<int> v{1,2,3,4,5,6};auto it = v.begin();// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变// v.reserve(100);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);

例如上面这些例子,他们都引起了底层空间的改变,就会导致it失效,如果在后面的代码中使用失效的迭代器就会导致程序崩溃。

要解决这个问题的方法也很简单,就是在修改之后重新赋值即可。

下面进行vector的模拟实现

	template<class T>class vector{public://vector的迭代器就是原生指针,这里写成模板的形式typedef T* iterator;typedef const T* const_iterator;//begin()相当于直接返回头指针iterator begin(){return _start;}const_iterator begin() const{return _start;}//end()相当于直接返回尾指针iterator end(){return _finish;}const_iterator end() const{return _finish;}//左闭右开//迭代器构造函数,这里写成模板支持更多类型template<class InputIterator>vector(InputIterator first, InputIterator last){while(first != last){push_back(*first);++first;}}//空构造函数vector():_start(nullptr), _finish(nullptr), _endofstorage(nullptr){}//拷贝构造//不能使用memcpy,因为这是浅拷贝,很可能会造成内存泄漏vector(const vector<T>& v):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){_start = new T[v.capacity()];//memcpy(_start, v._start, sizeof(T) * v.size());//这里与下面reserve是相同的问题for (size_t i = 0; i < v.size(); i++){_start[i] = v._start[i];//如果是自定义类型,这里事实上调用的是自定义类型的赋值操作}//这里由于是原生指针,并且是顺序存储因此可以直接相加_finish = _start + v.size();_endofstorage = _start + v.capacity();}//初始化n个val的vector,这里可以复用resize()vector(size_t n,const T& val = T()):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){resize(n, val);}//交换void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}//现代写法//这里使用传值方式传参是因为能够生成临时拷贝不会影响原数据//这里使用传引用返回是因为this出了作用域会销毁vector<T>& operator=(vector<T> v){swap(v);//相当于this->swap(v)return *this;}//析构~vector(){if (_start){delete[] _start;_start = _finish = _endofstorage = nullptr;}}//reserve()空间管理,同样不能使用memcpy(),会导致内存泄漏void reserve(size_t n){if (n > capacity()){size_t sz = size();T* temp = new T[n];if (_start){//memcpy(temp, _start, sizeof(T) * size());for (size_t i = 0; i < sz; i++){temp[i] = _start[i];//如果是自定义类型,这里事实上调用的是自定义类型的赋值操作}delete[] _start;}_start = temp;//_finish = _start + size()这样写是错的。//由于_start的改变会导致size()报错,这就是迭代器失效。//因为_start指向了新空间,但是_finish还是指向旧空间_finish = _start + sz;_endofstorage = _start + n;}}//申请n个空间初始化为val,这里复用reserve()void resize(size_t n,const T& val = T())//匿名对象{if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}}//尾插,这里自己实现需要注意扩容,但是也可以考虑直接复用insert()void push_back(const T& x){//if (_finish == _endofstorage) //{//	//扩容//	size_t newcapacity = capacity() == 0 ? 4 : capacity() *2;//	reserve(newcapacity);//}//*_finish = x;//++_finish;insert(end(), x);}//这里与尾插是一样的思路void pop_back(){erase(end());}//获得当前容器的容量size_t capacity() const{return _endofstorage - _start;}//获取当前容器中有效数据的个数size_t size() const{return _finish - _start;}//重载[],这里事实上相当于(*_start + pos)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 insert(iterator pos ,const T& x){assert(pos >= _start && pos <= _finish);if (_finish == _endofstorage){//扩容//这里如果直接扩容会引发迭代器失效,因为pos还是指向原来的位置//因此需要更新pos的位置,这里保存的时相对位置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--;}*pos = x;++_finish;}//iterator erase(iterator pos)//{//	 //检查 pos 是否在合法范围内//	if (pos < _start || pos >= _finish)//	{//		throw std::out_of_range("Iterator out of range");//	}//	 //从删除位置开始,将后续所有元素向前移动一位//	iterator it = pos;//	while (it < _finish - 1)//	{//		*it = *(it + 1);//		++it;//	}//	 //更新 _finish,减少容器大小//	--_finish;//	 //返回删除位置的下一个有效迭代器//	return pos;  // 注意:这里返回的是删除位置的下一个迭代器//}//只要把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;};

相关文章:

C++vector常用接口和模拟实现

C中的vector是一个可变容量的数组容器&#xff0c;它可以像数组一样使用[]进行数据的访问&#xff0c;但是又不像C语言数组空间是静态的&#xff0c;它的空间是动态可变的。 在日常中我们只需要了解常用的接口即可&#xff0c;不常用的接口查文档即可。 1.构造函数 //空构造…...

oracle查询归档日志使用量

1.统计最近30天的数据 SELECT TRUNC(first_time, DD) "日期", SUM(blocks * block_size) / 1024 / 1024 / 1024 "大小(GB)" FROM v$archived_log WHERE first_time > SYSDATE - 30 -- 统计最近30天的数据 GROUP BY TRUNC(first_time, DD) ORDER BY 1 D…...

计算机二级WPS Office第七套WPS演示

解题过程...

2025-03-26 学习记录--C/C++-PTA 6-3 求链式表的表长

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 6-3 求链式表的表长 本题要求实现一个函数&#xff0c;求链式表的表长。 函数接口定义&#xff1a; &…...

【Mysql】事务管理:原理、操作与应用

文章目录 一、事务概述二、事务的特性&#xff08;ACID&#xff09;原子性&#xff08;Atomicity&#xff09;一致性&#xff08;Consistency&#xff09;隔离性&#xff08;Isolation&#xff09;持久性&#xff08;Durability&#xff09; 三、事务的操作事务的提交方式查看和…...

PHP框架 ThinkPHP 漏洞探测分析

目录 1. PHP历史利用最多的漏洞有哪些&#xff1f; 2. 如何在信息收集的过程中收到框架信息&#xff1f;有什么根据&#xff1f; 3. ThinkPHP框架漏洞扫描有哪些工具&#xff1f;红队攻击有哪些方式&#xff1f; 漏洞扫描工具 红队攻击方式 4. TPscan工具的主要作用及实际…...

A Brief History: from GPT-1 to GPT-3

This is my reading notes of 《Developing Apps with GPT-4 and ChatGPT》. In this section, we will introduce the evolution of the OpenAI GPT medels from GPT-1 to GPT-4. GPT-1 In mid-2018, OpenAI published a paper titled “Improving Language Understanding …...

大模型在支气管肺癌预测及临床决策中的应用研究报告

目录 一、引言 1.1 研究背景与意义 1.2 研究目的 二、大模型预测支气管肺癌的原理与技术基础 2.1 大模型简介 2.2 数据收集与预处理 2.3 模型训练与优化 三、术前预测 3.1 病情评估 3.1.1 肿瘤大小、位置及分期预测 3.1.2 转移风险预测 3.2 手术风险预测 3.2.1 患…...

SylixOS 中 select 原理及使用分析

1、select接口简介 1.1 select接口使用用例 select 是操作系统多路 I/O 复用技术实现的方式之一。 select 函数允许程序监视多个文件描述符&#xff0c;等待所监视的一个或者多个文件描述符变为“准备好”的状态。所谓的”准备好“状态是指&#xff1a;文件描述符不再是阻塞状…...

软考笔记——软件工程基础知识

第五章节——软件工程基础知识 软件工程基础知识 第五章节——软件工程基础知识一、软件工程概述1. 计算机软件2. 软件工程基本原理3. 软件生命周期4. 软件过程 二、软件过程模型1. 瀑布模型2. 增量模型3. 演化模型&#xff08;原型模型、螺旋模型)4. 喷泉模型5. 基于构建的开发…...

FastGPT原理分析-数据集创建第二步:处理任务的执行

概述 文章《FastGPT原理分析-数据集创建第一步》已经分析了数据集创建的第一步&#xff1a;文件上传和预处理的实现逻辑。本文介绍文件上传后&#xff0c;数据处理任务的具体实现逻辑。 数据集创建总体实现步骤 从上文可知数据集创建总体上来说分为两大步骤&#xff1a; &a…...

基于Python的3D贴图制作技术研究与实践

摘要&#xff1a;本文深入探讨了利用Python进行3D贴图制作的技术&#xff0c;介绍了Python在3D图形领域的应用优势&#xff0c;阐述了3D贴图的基本原理和常见类型。详细讲解了借助Python的相关库&#xff0c;如Pillow、OpenCV、PyTorch3D开展3D贴图制作的流程&#xff0c;包括纹…...

【MySQL数据库】视图 + 三范式

视图 视图的基本介绍 MySQL中的视图&#xff08;View&#xff09;是一种虚拟的表&#xff0c;其内容是从一个或多个基本表中检索出来的。视图可以简化复杂的查询操作&#xff0c;提高查询效率&#xff0c;同时也可以对敏感数据进行安全性控制。下面是关于MySQL视图的一些基本…...

STM32学习笔记之存储器映射(原理篇)

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…...

如何通过数据可视化提升管理效率

通过数据可视化提升管理效率的核心方法包括清晰展示关键指标、及时发现和解决问题、支持决策优化。其中&#xff0c;清晰展示关键指标尤为重要。通过数据可视化工具直观地呈现关键绩效指标&#xff08;KPI&#xff09;&#xff0c;管理者能快速、准确地理解业务现状&#xff0c…...

数据结构:利用递推式计算next表

next 表是 KMP 算法的核心内容&#xff0c;下面介绍一种计算 next 表的方法&#xff1a;利用递推式计算 如图 6.3.1 所示&#xff0c;在某一趟匹配中&#xff0c;当对比到最后一个字符的时候&#xff0c;发现匹配失败&#xff08;s[i] ≠ t[j]&#xff09;。根据 BF 算法&…...

每日算法-250326

83. 删除排序链表中的重复元素 题目描述 思路 使用快慢指针遍历排序链表。slow 指针指向当前不重复序列的最后一个节点&#xff0c;fast 指针用于向前遍历探索。当 fast 找到一个与 slow 指向的节点值不同的新节点时&#xff0c;就将 slow 的 next 指向 fast&#xff0c;然后 …...

trino查询mysql报Unknown or incorrect time zone: ‘Asia/Shanghai‘

问题 trino查询mysql时报Error listing schemas for catalog mysql: java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.&#xff0c;trino的日志中看到Unknown or incorrect time zone…...

java学习笔记7——面向对象

关键字&#xff1a;static 类变量 静态变量的内存解析&#xff1a; 相关代码&#xff1a; public class ChineseTest {public static void main(String[] args) {System.out.println(Chinese.nation); //null 没赋值前System.out.println(Chinese.nation); //中国 静态变量赋值…...

leetcode day31 453+435

453 用最少数量引爆气球 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。 一支弓箭可以沿着 x 轴从不同点 完全垂直 地…...

C++三大特性之继承

1.继承的概念及定义 回忆封装 C Stack类设计和C设计Stack对比。封装更好&#xff1a;访问限定符类的数据和方法放在一起 -> 避免底层接口的暴露&#xff0c;数据更加的安全&#xff0c;程序的耦合性更高迭代器的设计&#xff0c;封装了容器底层结构&#xff0c;在不暴露底层…...

PyQt QDoubleSpinBox控件用法详解

QDoubleSpinBox 是 PyQt中用于输入浮点数的控件&#xff0c;支持键盘输入和上下箭头调整数值。与QtSpinBox不同&#xff0c;QtSpinBox是用于输入整数的控件。 关键属性和方法 QDoubleSpinBox 的关键属性和方法如下表所示&#xff1a; 方法/属性说明setRange(min, max)设置数…...

解决Vmware 运行虚拟机Ubuntu22.04卡顿、终端打字延迟问题

亲测可用 打开虚拟机设置&#xff0c;关闭加速3D图形 &#xff08;应该是显卡驱动的问题&#xff0c;不知道那个版本的驱动不会出现这个问题&#xff0c;所以干脆把加速关了&#xff09;...

查询Marklogic数据库,因索引配置造成的返回数据count不同的问题

查询Marklogic数据库&#xff0c;因索引配置造成的返回数据count不同的问题 一&#xff0c;问题&#xff1a; 目前由两个MarkLogic DB&#xff0c;其中A表示所有的数据库统称&#xff0c;包含于BCD&#xff1b; 调用查询接口&#xff0c;通过A和B入口且相同的查询条件去查询B…...

ctfshow做题笔记—栈溢出—pwn73、pwn74

目录 一、pwn73(愉快的尝试一下一把梭吧&#xff01;) 二、pwn74(噢&#xff1f;好像到现在为止还没有了解到one_gadget?) 前言&#xff1a; 抽空闲时间继续学习&#xff0c;记录了两道题&#xff0c;pwn74卡了几天哈哈。 一、pwn73(愉快的尝试一下一把梭吧&#xff01;) …...

026-zstd

zstd 以下为Zstandard&#xff08;zstd&#xff09;压缩算法从原理到代码实现的技术调研报告&#xff0c;结合流程图、结构图及完整C代码实现&#xff1a; 一、核心原理与技术架构 1.1 算法原理 Zstd基于LZ77衍生算法与熵编码&#xff08;FSE/Huffman&#xff09;的混合架构&…...

AF3 quat_to_rot函数解读

AlphaFold3 rigid_utils 模块的 quat_to_rot 函数的功能是把四元数转换为旋转矩阵,函数利用预定义的四元数到旋转矩阵的转换表 _QTR_MAT 来简化计算。 理解四元数到旋转矩阵的转换 源代码: _quat_elements = ["a", "b", "c", "d"]…...

Elasticsearch 的搜索功能

Elasticsearch 的搜索功能 建议阅读顺序&#xff1a; Elasticsearch 入门Elasticsearch 搜索&#xff08;本文&#xff09; 1. 介绍 使用 Elasticsearch 最终目的是为了实现搜索功能&#xff0c;现在先将文档添加到索引中&#xff0c;接下来完成搜索的方法。 查询的分类&…...

Vala编成语言教程-构造函数和析构函数

构造函数 Vala支持两种略有不同的构造方案&#xff1a;我们将重点讨论Java/C#风格的构造方案&#xff0c;另一种是GObject风格的构造方案。 Vala不支持构造函数重载的原因与方法重载不被允许的原因相同&#xff0c;这意味着一个类不能有多个同名构造函数。但这并不构成问题&…...

Mybatis-plus配置动态多数据源

前言&#xff1a;微服务架构中&#xff0c;有些模块中可能不同组件用不同数据源&#xff0c;或者做数据库主从集群需要读写分离&#xff0c;动态切换数据源&#xff0c;或不同方法需要不同数据源就需要一个快捷方便的方法。引用动态数据源组件dynamic-datasource-spring-boot-s…...