C++11基于范围的for循环vector容器扩容详解迭代器失效

news2025/1/11 1:40:06

目录

C++11基于范围for循环

vector容器扩容详解

迭代器失效

总结


C++11基于范围for循环

对于一个有范围的集合
来说在程序代码中指定循环的范围有时候是多余的,还可能犯错误。

为此C++11中引入了基于范围的for循环。

语法:

语法:

for (迭代的变量 : 迭代的范围)

{

        // 循环体。

}

对于一个vector<int>容器,我们一般会这样遍历:

 

但是基于范围的for循环是这样的:

 

它的原理就是从v01中取到一个内容赋值给变量val;然后在循环体中操作val;

记住他的原理,很重要!

迭代的范围不仅仅可以使用容器,也可以使用数组或者初始化列表,如下:

还有很重要的一点:

如果容器中的元素是结构体和类,迭代器变量应该申明为引用,加const约束表示只读。

我们演示一下类,代码如下:

#include <iostream>
#include <vector>
using namespace std;

class MyClass
{
public:
	string m_name;

	MyClass() { cout << "默认构造函数AA()。\n"; }

	MyClass(const string& name) : m_name(name) { cout << "构造函数,name=" << m_name << "。\n"; }

	MyClass(const MyClass& a) : m_name(a.m_name) { cout << "拷贝构造函数,name=" << m_name << "。\n"; }

	MyClass& operator=(const MyClass& a) { m_name = a.m_name;  cout << "赋值函数,name=" << m_name << "。\n";  return *this; }

	~MyClass() { cout << "析构函数,name=" << m_name<<"。\n"; }
};

int main()
{

    return 0;
}

首先我们需要先明白vector容器扩充的原理:

main函数代码如下:

int main()
{
    vector<MyClass> v;
	cout << "v.capacity()=" << v.capacity() << "----------------------------------\n";
	v.emplace_back("www");
	cout << "v.capacity()=" << v.capacity() << "----------------------------------\n";
	v.emplace_back("eee");
	cout << "v.capacity()=" << v.capacity() << "----------------------------------\n";
	v.emplace_back("rrr");
	cout << "v.capacity()=" << v.capacity() << "----------------------------------\n";

    return 0;
}

capacity指的是vector已使用的大小;

运行:

接下来我们一步一步分析;

vector容器扩容详解

首先我们使用了vector的无参构造,它已使用容量大小是0;

然后emplace_back()函数构造了一个m_name为"www"的对象,调用了一次MyClass的构造函数;

然后显示容量此时为1;

重点:

然后再次构造一个m_name为eee的对象,输出了三行日志,为什么呢?

首先vector容器原来的大小capacity()=1,1是无法满足两个元素的("www","eee"),所以需要扩充,但是vector容器的扩充分为四个步骤

1、申请一个新的地址,这个地址可以存放下"www",和"eee"的对象,这一步没有日志;

2、构造"eee"存放到新的地址,显示构造函数,name="eee"。

3、将原来地址中的"www"拷贝过来,显示拷贝构造,name="www"。

4、释放原来的内存,显示析构函数,name="www"。

知道了vector扩充的步骤,下面的日志大家可以自己分析了;

讲vector容器扩充的步骤,主要是为了分析日志,让大家不要对接下来的输出的日志感觉迷茫;

现在我们已知,该容器有三个元素,那么我们会怎么访问这三个元素呢?

我们首先想到的肯定是这样写:

for (auto a : v)
	cout << a.m_name << " ";
cout << endl;

auto可以自动推导出v的类型;

运行一下:

红框上面的我们已经介绍了,不会再迷茫了;

红框中的内容又输出了一堆,为什么呢?我们分析一下:

还记不记得上面讲的基于范围for循环原理?从迭代的范围中取到一个内容赋值给迭代的变量 

在这里就是从v中取到一个内容赋值给a;

v中都是什么内容呢?"www"、"eee"、"rrr"的对象,一共三个对象;

那么第一次循环,我们将"www"的对象赋值给a,会调用拷贝构造,显示拷贝构造函数,name=www。

然后我们循环体中显示www和一个空格(也就是第二行日志的开头)

然后因为我们是将"www"的对象拷贝给a,那么a使用完这个对象肯定要析构啊,所以调用了析构函数,显示析构函数,name=www。

至此前两行的日志已经解释完毕;下面的原理都一样,不解释了;

所以下面这张图我们应该明白了:

for循环输出一个内容,就要拷贝一次,析构一次,这肯定不是我们想要的结果对吧?

那么怎么办呢?

因为我们a是拷贝过来的副本,所以a才有必要析构它,但是如果a使用的就是vector容器中的对象,不是拷贝过来的副本,就没有必要析构它,因为他不归a所管; 

怎么让a是容器中的对象而不是拷贝的副本呢?引用;

如下:

没有拷贝构造,因为我们使用的是vector容器中的对象本身,不会发生拷贝,既然没拷贝就不会有拷贝构造的日志,a也不会析构它;

这样还不是最完美的,为什么呢?

因为我们的a现在拿到的不是拷贝副本,而是vector容器中真正的数据,那么如果a操作了vector容器中的数据还是比较危险的,所以a应该加上const,不可修改vector容器中的数据; 

如下:

所以这就是为什么:如果容器中的元素是结构体和类,迭代器变量应该申明为引用,加const约束表示只读。

迭代器失效

最后基于范围的for循环还要注意迭代器失效的问题,在vector容器中,使用resize()、reserve()、assign()、push_back()、pop_back()insert()、erase()等函数会引起vector容器的动态数组发生变化,可能导致vector迭代器失效

演示一下,迭代器失效,代码如下:

 

上面是正常情况下的运行结果,下面取消注释:

 

只有1,正常显示了,这是为什么呢?就是迭代器失效了

如果不知道为什么迭代器失效,说明上面的vector容器扩充的四个步骤没有学好 

我们分析一下:

首先第一次循环,先输出val和空格;此时val是第一个元素,所以输出了1;

然后v.push_back(2);这一行代码,由于原来的vector容器的数量不能满足再填充一个2进去,所以这行代码会触发vector容器的扩充;

扩充四个步骤:1、申请新地址;2、将新的内容填充到新地址;3、将原地址中的内容拷贝到新地址;4、释放原地址

当我们的v.push_back(2)运行完了之后,vector容器元素的地址已经发生了改变,但是我们的val还是在原来的地址中取内容,因为这是已经编译好的地址,同时原来的地址已经被释放了,所以输出了四个垃圾值;

最后注意:

如果我们想验证容器扩充之后,地址发生了改变,那么假设我们的容器是vector<int> aa({1,2,3,4,5});那么我们想要输出aa元素的首地址,千万不能这样写:&aa;因为这样获得的是vector容器的地址,在栈区;我们想要输出aa元素的首地址必须使用STL提供的函数,aa.data()这样就能获取aa元素的首地址;

总结

1、迭代的范围可以是数组名、容器名、初始化列表或者可迭代的对象(支持begin()、end()、++、==)。

2、数组名传入函数后,已退化成指针,不能作为容器名。

3、注意迭代器失效的问题。

4、输出vector元素的地址,必须使用vector中的data()函数,不能取地址vector对象;

本篇文章内容至此结束!感谢观看!

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

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

相关文章

一加11:新的赛场,“不温和”的答卷

《不要温和地走进那个良夜》是英国诗人狄兰托马斯创作于20世纪中期的一首享誉世界的诗歌&#xff0c;作者所表达出的在逆境中坚韧不屈、逆流而上的精神&#xff0c;激励了一代又一代人。1月4日&#xff0c;一加11发布会现场&#xff0c;一加中国区总裁李杰Louis借鉴了狄兰托马斯…

联合证券|近90亿大资金“跑步入场”,光伏板块掀涨停潮

早盘光伏板块掀起涨停潮&#xff0c;原因或是这些。 国产特斯拉全线降价 1月6日&#xff0c;据特斯拉我国官网&#xff0c;特斯拉国产车型大幅降价&#xff0c;对国产Model 3后驱版、高性能版&#xff0c;及Model Y后驱版、长续航版、高性能版等五款车型进行调价。Model 3起价…

DFMN 代码解读

目录 0. 环境配置 1. 运行程序 2. 读代码的思路 1&#xff09;model.py !! 关于继承 !! 关于网络结构组织 !! 关于 forward 2) 数据预处理 3&#xff09;train.py 0. 环境配置 很简单&#xff0c;提示缺包xxx&#xff0c;pip install xxx 就可以了 1. 运行程序 从…

NuxtJS服务器端入门

一、搜索引擎优化 1、什么是SEO 总结&#xff1a;seo是网站为了提高自已的网站排名&#xff0c;获得更多的流量&#xff0c;对网站的结构及内容进行调整和优化&#xff0c;以便搜索引擎 &#xff08;百度&#xff0c;google等&#xff09;更好抓取到优质网站的内容&#xff0c…

GCN图神经网络和LSTM的介绍和使用场景 中英文

GCN-LSTM 可以学习参考 英文内容部分源自youtube的教学视频 自己跟着英文敲的 给定一辆出租车行驶时在某个时间段的速度&#xff0c;下一个时刻速度会是多少&#xff1f;这是一个时间序列回归预测问题。获得了若干时间点的速度&#xff0c;目标是预测出租车速度序列中的下一个…

线性模型:AR、MA、ARMA、ARMAX、ARX、ARARMAX、OE、BJ等

目录 1 AR 1 2 MA 1 3 ARMA 1 4 ARMAX 2 5 ARX 2 6 ARARX 3 7 ARARMAX 3 8 OE 3 9 BJ 3 各种线性模型&#xff0c;这些模型算数学基础模型&#xff0c;不仅在计量经济学&#xff0c;也在工业控制等各领域有应用。包括AR、MA、ARMA、ARMAX、ARX、ARARMAX、OE、BJ等。 1 AR 自…

【疑难攻关】——floor报错注入

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座右…

mysql多表查询30个经典案例

mysql多表查询30个经典案例插入两张表一个dept一个emp插入dept表数据插入emp表数据1.列出每个部门里面有那些员工及部门名称;2.运维部门的收入总和&#xff1b;3.HR部入职员工的员工号4.财务部门收入超过5000元的员工姓名5.找出销售部收入最低的员工的入职时间&#xff1b;6.找…

5G NR标准: 第20章 5G的演进

第20章 5G的演进 NR 的第一个版本&#xff0c;第 15 版&#xff0c;侧重于对 eMBB 的基本支持&#xff0c;在某种程度上&#xff0c;URLLC.1 如前几章所述&#xff0c;第 15 版是为即将发布的 NR 未来发展构建的基础 . NR 演进将带来额外的功能并进一步提升性能。 附加功能不…

Netty原理示图

1. AWT事件驱动 2. Websocket协议 3. 基于多个反应器的多线程模式 4. Netty Reactor 工作架构图 5. Bootstrap引导过程 Channel Channel是Java NIO的基础。它表示一个开放的连接&#xff0c;进行IO操作。基本的 I/O 操作&#xff08; bind() 、 connect() 、 read() 和 write(…

什么是异常?异常可以看作你敲出来的bug

异常异常的体系抛异常try -catchfinally自定义异常作为初学者&#xff0c;在刚开始写代码的时候&#xff0c;差不多写一行代码都要见一行红吧异常的体系 这里我们首先需要知道的一点是&#xff0c;所有的异常其实都是类。我们所有的异常都是继承于Throwable这个大类的&#xff…

喜讯!神策分析 Android SDK 入选数据安全“星熠”案例

随着《数据安全法》和《个人信息保护法》的相继出台实施&#xff0c;标志着数据安全保护法治时代的真正到来&#xff0c;国家对数据安全的重视达到了前所未有的高度。在此背景下&#xff0c;神策数据全面落地数据开发利用和数据安全领域的技术推广与产业创新&#xff0c;神策分…

有哪些视频素材网站值得推荐?

高质量视频素材网站&#xff0c;免费、可商用&#xff0c;建议收藏&#xff01; 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYwNDUx 网站有超多视频素材&#xff0c;全部都是高清无水印&#xff0c;各种类型都有&#xff0c;像自然、城市、动物、科技、商业等等都…

【算法】哈希表

&#x1f600;大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#x1f62b;&#xff0c;但是也想日更的人✈。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4…

Unity3D打包Assetbundle丢失Shader问题

详情见&#xff1a;https://www.pianshen.com/article/5391338163/1、Unity3D在打包Assetbundle时&#xff0c;可能会遇到Shader丢失的问题&#xff0c;解决方法&#xff1a;打开Edit->Project Settings->Graphics&#xff0c;在Always Included Shaders列表添加上所需的…

微信小程序测试(简单项目测试)

Flex布局简介 布局的传统解决方案&#xff0c;基于盒状模型&#xff0c;依赖 display属性 position属性 float属性 什么是flex布局&#xff1f; Flex是Flexible Box的缩写&#xff0c;意为”弹性布局”&#xff0c;用来为盒状模型提供最大的灵活性。 任何一个容器都可以指…

小程序 - 起步:小程序的构成、宿主环境、协同工作和发布

小程序 - 起步:小程序的构成、宿主环境、协同工作和发布 Date: January 5, 2023 Sum: 小程序的构成、宿主环境、协同工作和发布 小程序简介 小程序与普通网页开发的区别 1. 运行环境不同 网页运行在浏览器环境中 小程序运行在微信环境中 2. API 不同 由于运行环境的不同…

P1308 [NOIP2011 普及组] 统计单词数————C++

题目 [NOIP2011 普及组] 统计单词数 题目描述 一般的文本编辑器都有查找单词的功能&#xff0c;该功能可以快速定位特定单词在文章中的位置&#xff0c;有的还能统计出特定单词在文章中出现的次数。 现在&#xff0c;请你编程实现这一功能&#xff0c;具体要求是&#xff1…

数字验证学习笔记——SystemVerilog芯片验证21 ——覆盖率类型

一、覆盖率类型 覆盖率是衡量设计验证完备性的一个通用词语。随着测试逐步覆盖各种合理的组合&#xff0c;仿真过程过程会慢慢勾画你的设计情况。覆盖率工具会在仿真过程中收集信息&#xff0c;然后进行后续处理并且得到覆盖率报告。通过这个报告找出覆盖之外的盲区&#xff0…

冒泡排序模拟qsort函数

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; 前言&#xff1a; 学习C语言&#xff0c;一般情况下都会接触到冒泡排序&#xff0c;你知道吗&#xff0c;用冒泡排序的思想可以模拟实现qsort函数&#xff08;库函数的一种&#xff0c;可以实现快排&#xff…