记录C++中,vector的迭代器在push_back以后扩容导致迭代器失效的问题

前言

vector是我们用到最多的数据结构,其底层数据结构是单端动态数组,由于数组的特点,vector也具有以下特性: ①O(1)时间的快速访问; ②顺序存储,所以插入到非尾结点位置所需时间复杂度为O(n),删除也一样; ③扩容规则: 当我们新建一个vector的时候,会首先分配给他一片连续的内存空间,如std::vector vec,当通过push_back向其中增加元素时,如果初始分配空间已满,就会引起vector扩容,其扩容规则在gcc下以2倍方式完成:

  • 首先重新申请一个2倍大的内存空间;
  • 然后将原空间的内容拷贝过来;
  • 最后将原空间内容进行释放,将内存交还给操作系统;

注意事项 :根据vector的插入和删除特性,以及扩容规则,我们在使用vector的时候要注意,在插入位置和删除位置之后的所有迭代器和指针引用都会失效,同理,扩容之后的所有迭代器指针和引用也都会失效。

原文链接:https://blog.csdn.net/qq_45311905/article/details/117020436

问题1:使用{}赋值,会丧失扩容功能

vector的最原始大小是0,如果使用{}方法去赋值,那么会丧失扩容功能

cpp 复制代码
#include <iostream>
#include <vector>

int main() {
	std::vector<int> numbers = {1, 2, 3, 4, 5};
	
	// 获取第二个元素的迭代器
	auto it = numbers.begin() + 1;
	
	// 在第二个位置插入一个新元素,导致vector扩容
	numbers.insert(numbers.begin() + 1, 10);
	
	// 尝试访问迭代器指向的元素,会导致未定义行为    会打印随机值
	std::cout << "Value at iterator: " << *it << std::endl;
	
	// 实际值:
	std::cout << "Value at iterator: " << numbers[1] << std::endl;
	
	return 0;
}

会发现打印随机值

如果不使用{}就没问题:

cpp 复制代码
#include <iostream>
#include <vector>

int main() {
	std::vector<int> numbers;
	numbers.push_back(1);
	numbers.push_back(2);
	numbers.push_back(3);
	numbers.push_back(4);
	numbers.push_back(5);
	
	
	// 获取第二个元素的迭代器
	auto it = numbers.begin() + 1;
	
	// 在第二个位置插入一个新元素,导致vector扩容
	numbers.insert(numbers.begin() + 1, 10);
	
	// 尝试访问迭代器指向的元素,会导致未定义行为    会打印随机值
	std::cout << "Value at iterator: " << *it << std::endl;
	
	// 实际值:
	std::cout << "Value at iterator: " << numbers[1] << std::endl;
	
	return 0;
}

问题2:在push_back()以后,继续使用迭代器会触发扩容导致迭代器失效

cpp 复制代码
#include <iostream>
#include <vector>

int main() {
	std::vector<int> numbers;
	
	size_t max_capacity = 0;
	
	
	max_capacity = numbers.capacity();
	std::cout<<"max:"<<max_capacity<<std::endl;		// 0
	
	// 第一次添加数据,会导致第一次扩容
	numbers.push_back(100);
	auto it = numbers.begin() + 0;
	std::cout<<"*it:"<<*it<<std::endl;
	std::cout<<"number[0]:"<<numbers[0]<<std::endl;
	std::cout<<std::endl;
	
	// 第二次添加数据,会导致第二次扩容,迭代器失效,下标法不会失效
	numbers.push_back(2);
	max_capacity = numbers.capacity();
	std::cout<<"max:"<<max_capacity<<std::endl;
	std::cout<<"*it:"<<*it<<std::endl;
	std::cout<<"number[0]:"<<numbers[0]<<std::endl;
	it = numbers.begin() + 0;
	std::cout<<"new *it:"<<*it<<std::endl;
	std::cout<<std::endl;
	
	// 第三次添加数据,会导致第三次扩容,但是发现迭代器并没有失效,下标法不会失效
	numbers.push_back(2);
	numbers.push_back(2);
	numbers.push_back(2);
	numbers.push_back(2);
	max_capacity = numbers.capacity();
	std::cout<<"max:"<<max_capacity<<std::endl;
	std::cout<<"*it:"<<*it<<std::endl;
	std::cout<<"number[0]:"<<numbers[0]<<std::endl;
	it = numbers.begin() + 0;
	std::cout<<"new *it:"<<*it<<std::endl;
	std::cout<<std::endl;
	
//  因为一种在增加,所以发现程序所占内存越来越大	
//	for (int i = 1; ; ++i) {
//		numbers.push_back(i);
//		if (numbers.size() > numbers.capacity()) {
//			max_capacity = numbers.size() - 1;
//			break;
//		}
//	}
	
	return 0;
}

原因是,在最开始的时候,vector的容量是0,随着push-back,会不断 x2 的去增加容量,但是增加容量的时候,最开始获取的迭代器指针去获取数据的方式就失效了,不过好在使用下标并不会失效。

相关推荐
做科研的周师兄5 分钟前
【机器学习入门】7.4 随机森林:一文吃透随机森林——从原理到核心特点
人工智能·学习·算法·随机森林·机器学习·支持向量机·数据挖掘
流星白龙8 分钟前
【Qt】3.认识 Qt Creator 界面
java·开发语言·qt
Vanranrr10 分钟前
nullptr vs NULL:C/C++ 空指针的演变史
c语言·c++
机灵猫16 分钟前
深入理解 Java 类加载与垃圾回收机制:从原理到实践
java·开发语言
weixin_3077791317 分钟前
AWS Redshift 数据仓库完整配置与自动化管理指南
开发语言·数据仓库·python·云计算·aws
切糕师学AI18 分钟前
【多线程】阻塞等待(Blocking Wait)(以C++为例)
c++·多线程·并发编程·阻塞等待
Sunsets_Red19 分钟前
差分操作正确性证明
java·c语言·c++·python·算法·c#
伐尘38 分钟前
【Qt】QTableWidget 自定义排序功能实现
开发语言·qt
【杨(_> <_)】1 小时前
SAR信号处理重要工具-傅里叶变换(二)
算法·信号处理·傅里叶分析·菲涅尔函数
第七序章1 小时前
【C++】AVL树的平衡机制与实现详解(附思维导图)
c语言·c++·人工智能·机器学习