【C++】vector详解:接口使用、迭代器、内存理解、与模拟实现

文章目录

  • 1. 前言
  • 2. 内存角度 理解
  • 3. vector的使用
    • 定义 | 构造函数
    • vector iterator
    • vector 空间增长问题
    • vector 增删查改
    • vector 迭代器失效
      • 避免迭代器失效的建议
  • 4. 如何理解 二维动态vector
  • 5. 模拟实现 vector
  • 6. 相关文档

1. 前言

vector 是 C++ 标准模板库(STL)中最常用的动态数组容器之一。提供了一种灵活的方式来存储和管理元素,具备以下特点:

  1. 可变大小数组vector 是一种动态大小的数组容器,能够自动调整存储空间以适应元素增减。

  2. 连续存储:元素在内存中采用连续存储方式,支持高效的随机访问,时间复杂度为 O(1)。

  3. 动态分配:当新元素插入时,如果当前容量不足,vector 会分配一个更大的新数组,并将现有元素复制过去。虽然这个过程代价较高,但通过预留额外空间来减少频繁的重新分配。

  4. 空间管理:不同实现可能采取不同的策略来平衡时间复杂度和空间使用,通常以对数增长的方式增加容量。

  5. 操作效率:在末尾添加和删除元素的时间复杂度为 O(1),而在中间或开头进行插入和删除则为 O(n)。

  6. 迭代器优势vector 的迭代器支持随机访问,提供了比其他序列容器(如 listdeque)更好的性能表现。


2. 内存角度 理解

根据vector的文档介绍,我们知道:

vector是表示大小可变数组的序列容器;,本质是一个封装了动态分配数组的类

如何理解这个容器?

在这里插入图片描述

根据上图,vector申请的空间在堆上,并由标志位记录此时vector的总容量,当容量不够时根据规则进行扩容;


3. vector的使用

定义 | 构造函数

构造函数声明描述
vector()无参构造函数
vector(size_type n, const value_type& val = value_type())构造并初始化 n 个元素为 val
vector(const vector& x)拷贝构造函数
vector(InputIterator first, InputIterator last)使用迭代器范围进行初始化构造

vector iterator

接口说明描述
begin()获取第一个数据位置的 iterator / const_iterator
end()获取最后一个数据的下一个位置的 iterator / const_iterator
rbegin()获取最后一个数据位置的 reverse_iterator
rend()获取第一个数据前一个位置的 reverse_iterator

在这里插入图片描述


vector 空间增长问题

接口说明描述
size()获取数据个数
capacity()获取容量大小
empty()判断是否为空
resize(size_type n)改变 vector 的大小
reserve(size_type n)改变 vector 的容量
  • capacity() 接口 在 vsg++下分别运行会有以下结果:
    • vs下capacity是按1.5倍增长的,g++是按2倍增长的。
    • 即capacity的增长倍数并非固定的,而是根据具体需求定义的
    • vs是PJ版本STL,g++是SGI版本STL。
  • reserve只负责开辟空间,如果确定需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
  • resize在开空间的同时还会进行初始化,影响size

vector 增删查改

接口说明描述
push_back(const value_type& val)尾部插入元素 val
pop_back()尾部删除最后一个元素
find查找元素(算法模块实现,不是 vector 的成员接口)
insert(iterator position, const value_type& val)在指定位置之前插入元素 val
erase(iterator position)删除指定位置的元素
swap(vector& other)交换两个 vector 的数据空间
operator[](size_type index)像数组一样访问元素

vector 迭代器失效

  • 迭代器作为一种抽象数据类型,使算法在操作不同的数据结构时不必关心这些数据结构的具体实现;

  • 对于vector的迭代器来说,其底层本质是对指针进行了封装(原生态指针T*);因此对于迭代器失效,本质就是指针指向的空间被销毁了,因此指针失效了;

    • 使用被释放的空间,显然结果就是程序崩溃;
    • 即使用失效的迭代器,可能会导致程序崩溃

在使用 std::vector 时,有几种操作可能导致迭代器失效。下面是一些常见的情况及其代码示例:

  1. 插入元素

当向 vector 中插入元素时,如果当前容量不足,vector 会重新分配内存,导致所有迭代器失效。

#include <iostream>
#include <vector>int main() {std::vector<int> vec = {1, 2, 3};auto it = vec.begin(); // 保存迭代器vec.push_back(4); // 可能导致迭代器失效// 使用失效的迭代器std::cout << *it << std::endl; // 未定义行为return 0;
}
  1. 删除元素

删除元素会导致被删除元素后的所有元素的迭代器失效。

#include <iostream>
#include <vector>int main() {std::vector<int> vec = {1, 2, 3};auto it = vec.begin(); // 保存迭代器vec.erase(it); // 删除第一个元素,it 现在失效// 使用失效的迭代器std::cout << *it << std::endl; // 未定义行为return 0;
}
  1. 清空容器

调用 clear() 方法将删除 vector 中的所有元素,使得所有指向这些元素的迭代器失效。

#include <iostream>
#include <vector>int main() {std::vector<int> vec = {1, 2, 3};auto it = vec.begin(); // 保存迭代器vec.clear(); // 清空容器,it 失效// 使用失效的迭代器std::cout << *it << std::endl; // 未定义行为return 0;
}
  1. 重新分配

如果通过改变 vector 的大小(例如 resize)并增加容量,现有迭代器也会失效。

#include <iostream>
#include <vector>int main() {std::vector<int> vec = {1, 2, 3};auto it = vec.begin(); // 保存迭代器vec.resize(5); // 可能导致迭代器失效// 使用失效的迭代器std::cout << *it << std::endl; // 未定义行为return 0;
}

避免迭代器失效的建议

  • 重新获取迭代器:在进行插入或删除操作后,可以重新获取迭代器。
  • 使用 reserve:如果知道 vector 将要存储的元素数量,可以提前调用 reserve 来避免多次内存分配。
  • 使用范围for循环:尽量使用范围for循环来避免直接操作迭代器。

4. 如何理解 二维动态vector

我们以一个杨辉三角的例子举例,如果想打印高度为n的杨辉三角,可以用二维的vector,比如下面的代码:

void printPascalsTriangle(int numRows) {// 创建一个二维向量来存储杨辉三角std::vector<std::vector<int>> triangle(numRows);// 构建杨辉三角的每一行for (int i = 0; i < numRows; ++i) {triangle[i].resize(i + 1); // 调整每一行的大小以容纳相应数量的元素triangle[i][0] = 1; // 每行的第一个元素设为 1triangle[i][i] = 1; // 每行的最后一个元素设为 1// 填充当前行的中间元素for (int j = 1; j < i; ++j) {triangle[i][j] = triangle[i - 1][j - 1] + triangle[i - 1][j]; // 根据杨辉三角性质计算}}// 打印杨辉三角for (const auto& row : triangle) {for (int num : row) {std::cout << num << " "; // 输出当前行的每个数字}std::cout << std::endl; // 换行}
}

在刚初始化二维数组时,是这样的:
在这里插入图片描述
再填入相关数据后,是这样的:

在这里插入图片描述


5. 模拟实现 vector

👇 模拟实现部分在 👇

C++ vector类的模拟实现


6. 相关文档

  • 关于vector 的相关文档资料,可以参考下面的链接:
    • cppreference - vector
    • C++ Standard Library Documentation

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

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

相关文章

万界星空科技数字孪生:解锁制造业未来,重塑智慧工厂新纪元

万界星空科技的数字孪生技术是一项创新的技术解决方案&#xff0c;它深度融合了工业大数据、物联网&#xff08;IoT&#xff09;、人工智能&#xff08;AI&#xff09;等先进技术&#xff0c;为制造业工厂提供了一个高度智能化、可视化的运营管理系统。以下是对万界星空科技数字…

《程序猿之Redis缓存实战 · 集合类型》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

「OC」探索 KVC 的基础与应用

「OC」KVC的初步学习 文章目录 「OC」KVC的初步学习前言介绍KVC的相关方法key和keyPath的区别KVC的工作原理KVO的setValue:forKey原理KVO的ValueforKey原理 在集合之中KVC的用法1. mutableArrayValueForKey: 和 mutableArrayValueForKeyPath:2. mutableSetValueForKey: 和 muta…

Java项目实战II基于Java+Spring Boot+MySQL的智能物流管理系统(文档+源码+数据库)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者 一、前言 随着电子商务的蓬勃发展&#xff0c;物流行业迎来了前所未有的挑战与机遇。传统物流管理方式在应对海…

PDCA优化任务流程

这里写目录标题 一、背景二、PDCA重要性与必要性概念PDCA循环的重要性 三、PDCA分析这次任务的执行任务描述分析原因&#xff1a;结合PDCA分析&#xff1a;提高办法&#xff1a; 四、总结 一、背景 汇报任务完成情况&#xff0c;未提交实际成果。 本次总结旨在通过PDCA循环的视…

二值图像的面积求取的两种方法及MATLAB实现

一、引言 面积在数字图像处理中经常用到&#xff0c;在MATLAB中&#xff0c;计算二值图像的面积通常可以通过两种主要方法实现&#xff1a;遍历法和直接利用bwarea函数。下面将分别介绍这两种方法的原理和相应的MATLAB代码示例。 二、遍历法计算二值图像面积的原理和MATLAB代码…

如何创建虚拟环境并实现目标检测及验证能否GPU加速

创建虚拟环境&#xff1a; 先创建一个虚拟python环境&#xff0c;敲如下代码 然后再到该虚拟环境里面安装自己想要的包 激活虚拟环境 然后再聚类训练这些 验证GPU加速 阿里源 pip install torch torchvision -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mir…

Appinventor2 多屏幕之间如何共享过程?

先说结论&#xff1a;不能共享&#xff0c;但可以变通&#xff0c;这个问题上没有完美方案&#xff01; Appinventor2 多屏幕之间如何共享过程&#xff1f;或者说如何跨屏幕调用其他屏幕的过程&#xff1f; 相信有很多人有过这样的问题&#xff0c;但是目前来看每个屏幕都是独…

Linux下驱动开发实例

驱动开发 驱动与硬件的分离 在传统的嵌入式系统开发中&#xff0c;硬件信息往往是直接硬编码在驱动代码中的。这样做的问题是&#xff0c;当硬件发生变化时&#xff0c;比如增加或更换设备&#xff0c;就需要修改驱动程序的代码&#xff0c;这会导致维护成本非常高。因此&…

机器学习周报(9.23-9.29)

文章目录 摘要Abstract1 自监督学习&#xff08;Self-Supervised Learning&#xff09;1.1 BERT1.1.1 Masking Input1.1.2 Next Sentence Prediction1.1.3 BERT的使用方式 1.2 Why does BERT work?1.3 Multi-lingual BERT 2 pytorch中tensor相关函数学习使用2.1 张量拼接与拆分…

4G模组SIM卡电路很简单,但也要注意这些坑

上次水SIM卡相关的文章&#xff0c;还是上一次&#xff1b; 上一篇文章里吹牛说&#xff0c;跟SIM卡相关的问题还有很多&#xff0c;目的是为下一篇文章埋下伏笔&#xff1b;伏笔埋是埋下了&#xff0c;但如果债老是不还&#xff0c;心里的石头就总悬着&#xff0c;搞不好老板…

MAC的几个常见的快捷方式

1.mac 查看图片好的方式 默认查看图片的方式无法直接切换上一张下一张 解决方法&#xff1a; 1.&#xff08;最好的方法&#xff09;选中图片直接按空格&#xff0c;进入快速预览图片 2.就是全部选中然后打开&#xff0c;但是说实话有点奇怪&#xff0c;而且很占内存 3.直接显示…

Linux 信号捕捉

我们知道信号的处理不是即时的&#xff0c;进程在合适的时机才会处理信号&#xff0c;而这个时机就比如从内核态返回用户态。 1. 用户态与内核态 在操作系统中&#xff0c;用户态&#xff08;User Mode&#xff09;和内核态&#xff08;Kernel Mode&#xff09;是两种不同的C…

安卓主板_MTK4G/5G音视频记录仪整机及方案定制

音视频记录仪方案&#xff0c;采用联发科MT6877平台八核2* A78 6* A55主频高达2.4GHz, 具有高能低耗特性&#xff0c;搭载Android 12.0智能操作系统&#xff0c;可选4GB32GB/6GB128GB内存&#xff0c;运行流畅。主板集成NFC、双摄像头、防抖以及多种无线数据连接&#xff0c;支…

如何在 Kubernetes 上部署和配置开源数据集成平台 Airbyte?

在 Kubernetes 上部署和配置 Airbyte 是一个复杂但非常有价值的过程&#xff0c;特别是对于需要强大数据集成和数据处理能力的企业或团队。Airbyte 是一个开源的数据集成平台&#xff0c;允许用户从各种来源提取数据并加载到目标存储中。其强大的插件系统支持多种数据源与目标&…

新能源汽车储充机器人:能源高效与智能调度

新能源汽车储充机器人&#xff1a;开启能源高效利用与智能调度的未来之门 随着全球能源危机的日益加剧和环境污染问题的不断恶化&#xff0c;新能源汽车成为了未来交通领域的重要发展方向。然而&#xff0c;新能源汽车的普及不仅需要解决电池技术的瓶颈&#xff0c;还需要构建一…

labview更换操作系统后打开原VI闪退

labview更换操作系统后打开原VI闪退 问题描述&#xff1a; Windows11由家庭版更换为专业版后&#xff0c;重新安装labview2021&#xff0c;打开原来的项目&#xff0c;项目管理器可以正常打开&#xff0c;但是打开VI却闪退&#xff0c;并报错如下 出现这种原因主要是labview在…

通信工程学习:什么是LAN局域网、MAN城域网、WAN广域网

LAN局域网、MAN城域网、WAN广域网 LAN&#xff08;Local Area Network&#xff0c;局域网&#xff09;、MAN&#xff08;Metropolitan Area Network&#xff0c;城域网&#xff09;和WAN&#xff08;Wide Area Network&#xff0c;广域网&#xff09;是计算机网络中根据覆盖范围…

vue组合式api

一、ref&#xff08;基本类型数据&#xff0c;对象类型数据&#xff09; 1.作用&#xff1a;定义响应式变量 2.语法&#xff1a;let xxx ref(初始值) 3.返回值&#xff1a;一个RefImpl的实例对象&#xff0c;简称ref对象&#xff0c;ref对象的value属性是响应式的。 4.注意…

【MySQL】视图、用户和权限管理

目录 视图创建视图数据修改影响删除视图视图优点 用户和权限管理查看当前的数据库拥有用户信息创建用户修改密码删除用户权限授权回收权限 视图 视图就是相当于创建一个表&#xff0c;将查询到的结果集给存储起来。像使用复杂的多表查询查询到的结果集就不可以对结果集操作。而…