C++Vector类详解

news2024/11/22 10:05:47

目录

1.Vector介绍

2.Vector的常见使用

   2.1 vector构造函数

   2.2 vector iterator使用

   2.3 vector空间增长问题

   2.4 vector增删改查

   2.5 vector迭代器失效问题

3.Vector深度剖析及模拟实现

   3.1 模拟实现(可跳过)

   3.2 不使用memcpy剖析


1.Vector介绍

 

  1. vector是表示可变大小数组的序列容器。
  2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
  3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
  4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
  5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
  6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list 统一的迭代器和引用更好。

2.Vector的常见使用

   2.1 vector构造函数

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

   2.2 vector iterator使用

iterator的使用接口说明
begin+end
获取第一个数据位置的 iterator/const_iterator , 获取最后一个数据的下一个位置的iterator/const_iterator
rbegin+rend
获取最后一个数据位置的 reverse_iterator ,获取第一个数据前一个位置的reverse_iterator

 简单使用例子:

void test1()
	{
		vector<int> V;
		V.push_back(1);
		V.push_back(2);
		V.push_back(3);
		V.push_back(4);
		vector<int>::iterator it = V.begin();
		while (it != V.end())
		{
			cout << *it << ' ';
			++it;
		}
		cout << endl;
		//反向迭代器
		vector<int>::reverse_iterator rit = V.rbegin();
		while (rit != V.rend())
		{
			cout << *rit << ' ';
			++rit;
		}
		cout << endl;
	}

 

   2.3 vector空间增长问题

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

测试vector的默认扩容机制:

void TestVectorExpand()
	{
		size_t sz;
		vector<int> v;
		sz = v.capacity();
		cout << "making v grow:\n";
		for (int i = 0; i < 100; ++i)
		{
			v.push_back(i);
			if (sz != v.capacity())
			{
				sz = v.capacity();
				cout << "capacity changed: " << sz << '\n';
			}
		}
	}

vs下运行:

gcc下运行: 

  •  capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
  • reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
  • resize在开空间的同时还会进行初始化,影响size。
	void test2()
	{
		vector<int> v;

		// set some initial content:
		for (int i = 1; i < 10; i++)
			v.push_back(i);

		v.resize(5);
		v.resize(8, 100);
		v.resize(12);
		cout << v.size() << endl;
		cout << "v contains:";
		for (size_t i = 0; i < v.size(); i++)
			cout << ' ' << v[i];
		cout << endl;
	}

 使用reserve提前设置好容量:

   2.4 vector增删改查

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

 测试代码:

void test3()
	{
		vector<int> v{ 1,2,3,4 };//列表方式初始化,C++11新语法
		v.push_back(5);
		v.push_back(6);
		v.pop_back();
		for (size_t i = 0; i < v.size(); i++)
		{
			cout << v[i] << ' ';
		}
		cout << endl;
		vector<int>::iterator pos = find(v.begin(), v.end(), 3);
		if (pos != v.end())
		{
			v.insert(pos, 0);
		}
		pos = find(v.begin(), v.end(), 3);
		v.erase(pos);
		for (size_t i = 0; i < v.size(); i++)
		{
			cout << v[i] << ' ';
		}
		cout << endl;

	}

   2.5 vector迭代器失效问题

细心的朋友,可能已经发现我上面圈出来的重复find查找了一次,这是因为如果不再find给pos赋值,insert后不接受迭代器返回值继续erase会造成迭代器失效问题。 

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。

对于vector可能会导致其迭代器失效的有效的操作有:

  • 会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back等。

        扩容后原来的pos已经失效,变为野指针。

        若不扩容insert后pos指向插入元素。

  • 指定位置元素的删除——erase
        erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是: 如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。
迭代器失效解决办法: 在使用前,对迭代器 重新赋值 即可
 
修改上面例子代码示例如下:
        vector<int>::iterator pos = find(v.begin(), v.end(), 3);
		if (pos != v.end())
		{
			pos=v.insert(pos, 0);
            //pos当前指向0
		}
        //删除3
		++pos;
		v.erase(pos);

3.Vector深度剖析及模拟实现

   3.1 模拟实现(可跳过)

        私有成员变量:与上图保持一致

		iterator _start;
		iterator _finish;
		iterator _end_of_storage;

        构造函数:

         拷贝构造函数:(现代写法)

swap:

         赋值运算符重载:(现代写法)

         析构函数:

         迭代器:

         size和capacity:

        reserve:(为什么不使用memcpy在后面将解)

         resize:

         operator[ ]:

        insert:

         erase:

         push_back,pop_back():(复用insert,erase)

   3.2 不使用memcpy剖析

        memcpy是浅拷贝

1.memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中。
2. 如果拷贝的是自定义类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。

 假设一个vector<vector<int>>类型,实际内存分配:

 memcpy分配:(浅拷贝,释放2次空间,第二次为野指针造成内存泄漏)

 采取深拷贝(自己实现):

 


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

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

相关文章

【LeetCode】106. 从中序与后序遍历序列构造二叉树

1.问题 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1 输入&#xff1a;inorder [9,3,15,20,7], postorder [9,15,7,20,3] 输出&#…

世优科技AI数字人产品“世优BOTA”发布!全面提升AI虚拟员工能力

2023年4月20日,“世优BOTA”产品发布会在北京圆满落幕。此次发布会上,世优(北京)科技有限公司(以下简称“世优科技”)正式发布了新一代AI数字人现象级产品——“世优BOTA”。来自现实世界的LiveVideoStack创始人包研与来自数字世界的世优虚拟主持人「阿央」通过新颖的互动开场方…

JDK多版本配置及切换版本不生效问题解决

一、准备工作 首先你要有多个版本的jdk&#xff0c;如果没有请移至 https://www.oracle.com/java/technologies/downloads/ 下载&#xff0c;具体下载方法可参考&#xff1a;Java同学入职环境安装全讲解 二、配置环境变量 在环境变量中配置多个JAVA_HOME&#xff0c;我这里…

Java中TCP通信的实现

0、TCP通信 传输控制协议&#xff08;TCP&#xff0c;Transmission Control Protocol&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议&#xff0c; 如果使用了 WireShark 工具&#xff0c;可以看到一次TCP连接建立时的整个过程。 1、单向通信 单向通信中&…

案例01-tlias智能学习辅助系统01-增删改查+参数传递

目录 1、需求说明&#xff1a;实现对部门表和员工表的增删改查 2、环境搭建 3、部门管理 3.1 查询部门 3.2 前后端联调 3.3 删除部门 3.4 新增部门 3.5 根据ID查询数据 3.5 修改部门 总结&#xff08;Controller层参数接收&#xff09;&#xff1a; 4、员工管理 4.…

CMIP6:WRF模式动力降尺度、单点降尺度、统计方法区域降尺度

气候变化关系到农业、生态系统、社会经济和人类生存与发展&#xff0c;是当今世界关注的重点问题之一。IPCC&#xff08;Intergovernmental Panel on Climate Change&#xff09;第6次评估报告指出&#xff0c;自 20 世纪 50 年代以来&#xff0c;从全球平均气温和海温升高…

一个关于Mybatis和spring的公共组件starter

utils-springboot-starter 介绍使用说明 介绍 一个关于Mybatis和spring的公共组件starter&#xff0c;目前包含以下功能&#xff1a; 接口请求日志SQL执行日志数据自动加解密数据自动脱敏服务治理方面&#xff1a; 接口限流接口熔断降级&#xff1a;CPU、内存、异常数、异常率…

51.网页设计规则#1_字体设计

一些概念 字体排版 排版是安排字体的艺术和技术&#xff0c;以使书面语言在显示时清晰、可读和吸引人。&#xff08;来自维基百科翻译&#xff09; serif字体和sans-serif字体 serif字体 ● 创造一个传统/经典的外观和感觉 ● 体现出可信度 ● 适合长文本 sans-serif字体 …

【JavaScript】7.DOM的操作元素

DOM 的操作元素 JavaScript 的 DOM 操作可以改变网页内容、结构和样式&#xff0c;我们可以利用 DOM 操作元素来改变元素里面的内容 、属性等 1. 改变元素内容 element.innerText&#xff1a;从起始位置到终止位置的内容, 但它去除 html 标签&#xff0c; 同时空格和换行也会…

Pytorch深度学习笔记(十)多分类问题

课程推荐&#xff1a;09.多分类问题_哔哩哔哩_bilibili 目录 1. 多分类模型 2. softmax函数模型 3. Loss损失函数 4.实战MNIST Dataset 之前&#xff0c;在逻辑斯蒂回归中我们提到了二分类任务&#xff0c;现在我们讨论多分类问题。 1. 多分类模型 与二分类不同的是多分…

基于C#asp.net心里咨询服务网站系统

功能模块&#xff1a; 主要分为管理员和注册用户&#xff0c;注册用户可以查看所有人发布的心里文章&#xff0c;情感在线问答&#xff0c;查询相似问题&#xff0c;以及进入论坛进行交流&#xff08;发帖跟帖评论收藏等&#xff09;后台管理主要是针对个人信息修改 管理员对注…

SpringBoot自动装配机制的原理

自动装配 简单来说&#xff0c;就是自动去把第三方组件的Bean装载到IOC容器里面。不需要开发人员再去写Bean相关的一个配置。 在SpringBoot应用里面&#xff0c;只需要在启动类上去加上SpringBootApplication注解就可以实现自动配置&#xff0c;SpringBootApplication注解它是…

DSPC174 3BSE005461R1码垛工业机器人安装调试的13个步骤

​ DSPC174 3BSE005461R1码垛工业机器人安装调试的13个步骤 ABB码垛工业机器人安装调试的13个步骤 最近工业机器人市场上&#xff0c;调试工作比较火爆&#xff0c;单个项目动辄几十台机器人同时调试&#xff0c;开出的日薪达到1500-2000元。拥有如此庞大的市场需求和丰厚收入…

Hudi数据湖技术之核心概念

目录 1 基本概念1.1 时间轴Timeline1.2 文件管理1.3 索引Index 2 存储类型2.1 计算模型2.1.1 批式模型&#xff08;Batch&#xff09;2.1.2 流式模型&#xff08;Stream&#xff09;2.1.3 增量模型&#xff08;Incremental&#xff09; 2.2 查询类型&#xff08;Query Type&…

力扣:通过《84.柱状图中最大的矩形》求解《85. 最大矩形》

84. 柱状图中最大的矩形 85. 最大矩形 84.柱状图中最大的矩形&#xff1a; 单调栈求解问题范围&#xff1a; 输出每个数左边第一个比它小的数 单调栈例题&#xff1a; Acwing 830. 单调栈 #include <iostream>using namespace std;const int N 100010; int stk[N],tt …

再多猜一次就爆炸(小黑子误入)

目录 猜数字游戏 游戏设计思路 1.电脑随机生成一个数 2.猜数字 3.输入我是ikun&#xff0c;泰裤辣! 否则电脑将在一分钟后关机 游戏运行效果 源码 代码分析 代码实现关键语句 strcmp() rand()与srand() 时间戳time() 寄语 猜数字游戏 游戏设计思路 1.电脑随机生…

C语言_Printf函数返回值

目录 1. 嵌套结构 2. Printf 函数返回值 在了解Printf 函数的返回值之前&#xff0c;先来了解下什么叫嵌套结构。 1. 嵌套结构 这里直接举个例子进行介绍&#xff1a; strlen 函数计算字符串长度&#xff0c;显然打印的结果是 3 但是如果采用嵌套结构&#xff08;简单来说就…

【深度学习】基于华为MindSpore的手写体图像识别实验

1 实验介绍 1.1 简介 Mnist手写体图像识别实验是深度学习入门经典实验。Mnist数据集包含60,000个用于训练的示例和10,000个用于测试的示例。这些数字已经过尺寸标准化并位于图像中心&#xff0c;图像是固定大小(28x28像素)&#xff0c;其值为0到255。为简单起见&#xff0c;每…

看完这篇文章你就彻底懂啦{保姆级讲解}-----(LeetCode刷题142环形链表II) 2023.4.24

目录 前言算法题&#xff08;LeetCode刷题142环形链表II&#xff09;—&#xff08;保姆级别讲解&#xff09;分析题目&#xff1a;算法思想环形链表II代码&#xff1a;补充 结束语 前言 本文章一部分内容参考于《代码随想录》----如有侵权请联系作者删除即可&#xff0c;撰写…

ESP32设备驱动-LIS3MDL磁场传感器驱动

LIS3MDL磁场传感器驱动 文章目录 LIS3MDL磁场传感器驱动1、LIS3MDL介绍2、硬件准备3、软件准备4、驱动实现1、LIS3MDL介绍 LIS3MDL 具有4/8/12/16 高斯的用户可选满量程。自检功能允许用户在最终应用中检查传感器的功能。该设备可以被配置为生成用于磁场检测的中断信号。 LIS…