【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题)

这篇具有很好参考价值的文章主要介绍了【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题),从零开始的C++生活,c++,java,开发语言,算法,linux,学习,蓝桥杯
送给大家一句话:

世界在旋转,我们跌跌撞撞前进,这就够了 —— 阿贝尔 加缪

1 前言

我们之前实现了手搓vector,但是当时依然有些问题没有解决:

  1. 迭代器区间拷贝(非法的间接寻址问题)
  2. 迭代器失效问题
  3. 使用memcpy拷贝问题

接下来,我们一点一点来解决这些问题!!!

2 迭代器区间拷贝

来看这个这个构造函数:

		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}

这个是对迭代器区间进行的构造函数,思路很简单,把迭代器区间的数据依次尾插就可以了(这里之所以另外使用一个新的模版,而不是使用vector类的模版,是为了兼容更多的数据类型)。这样就可以通过一个现有的类型来构造容器。
但是出乎意料的是出现了一个问题: C2100 非法的间接寻址 (编译层面的问题) 。非法的间接寻址的造成原因有很多:

  1. 空指针引I用:当一个指针没有被初始化或者为NULL时,对它进行间接寻址操作会导致非法访问
  2. 野指针引用:当一个指针超出了它所指向的内存范围,或者已经被释放但仍然被引用时,进行间接寻址操作也会导致非法访问。
  3. 类型不匹配:如果试图将指针转换为不兼容的类型进行间接寻址,也会导致非法访问。

我们分析一下我们遇到的问题是那种问题?空指针引用吗?不可能!野指针引用吗?也不可能!!! 那么真相只有一个:我们遇到了类型不匹配的问题,那这是来自哪里的呢???,经过我的排除法(注释不同的代码块来进行查找),得到了结果

vector<int> v1(5,6);

这一行代码是我们出错的根源,为什么这个构造没有去使用vector(size_t n,T val = T()),而是使用我们的vector(InputIterator first, InputIterator last),因为第二个函数与(5,6)的类型更匹配,编译器会寻找最合适的函数。

解决方法也是十分暴力:多枚举几个 构造函数:

vector(size_t n,T val = T())
vector(int n,T val = T());
vector(long long n,T val = T());

这样就会优先匹配vector(int n,T val = T());了,我们的问题也就解决了。

3 迭代器失效问题

这个问题主要出现在我们的插入操作(insert)和删除操作(erase)。来看:

void vector_test7() {
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	v1.push_back(7);


	vector<int>::iterator it = v1.begin() + 3;// 4
	cout << *it << endl;
	v1.insert(3, 40);
	cout << *it << endl;
}

这个执行的结果是:
【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题),从零开始的C++生活,c++,java,开发语言,算法,linux,学习,蓝桥杯
迭代器的指向发生了改变,我们实现的迭代器的底层是指针,我们插入之后指针位置不变,而数组元素改变,自然会产生不一样的结果。这个问题看起来不严重,那我们再来看:

void vector_test7() {
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	v1.push_back(7);
	v1.push_back(8);

	vector<int>::iterator it = v1.begin() + 3;// 4
	cout << *it << endl;
	v1.insert(3, 40);
	cout << *it << endl;
}

【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题),从零开始的C++生活,c++,java,开发语言,算法,linux,学习,蓝桥杯
为什么这里出现了乱码???我们代码和之前的区别是什么???一个进行了扩容,一个没进行扩容。扩容之后vector的_start发生了改变,自然我们的指针也失去了对应作用。 迭代器就失效了,这个解决办法也很简单,就是插入之后不要使用之前的迭代器!!!一定要对迭代器进行更新。

再来看erase中的问题:

void vector_test7() {
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	//v1.push_back(6);
	//v1.push_back(7);
	//v1.push_back(8);

	vector<int>::iterator it = v1.begin();
	//删除偶数
	while (it != v1.end())
	{
		if (*it % 2 == 0)
		{
			v1.erase(it);
		}
		++it;
	}
	print_vector(v1);
}

这样运行起来是没有问题的,那么再来看:

void vector_test7() {
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(4);
	v1.push_back(5);
	//v1.push_back(6);
	//v1.push_back(7);
	//v1.push_back(8);

	vector<int>::iterator it = v1.begin();
	//删除偶数
	while (it != v1.end())
	{
		if (*it % 2 == 0)
		{
			v1.erase(it);
		}
		++it;
	}
	print_vector(v1);
}

现在出现了:
【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题),从零开始的C++生活,c++,java,开发语言,算法,linux,学习,蓝桥杯
这个问题,问题的来源也很简单,我们迭代器在删除之后没有改变位置,但是_start的元素发生了改变,也就是相当于 it 向后移动了两次,为了避免这个情况我们可以:

	while (it != v1.end())
	{
		if (*it % 2 == 0)
		{
			v1.erase(it);
		}
		else
		{
			++it;
		}
		
	}

这样就可以了:
【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题),从零开始的C++生活,c++,java,开发语言,算法,linux,学习,蓝桥杯
需要注意的一点是,我们的操作是以g++标准来进行的(如果删除会进行缩容,也会出现错误,迭代器就不能进行++了),所以 在VS环境下,vector 容器在erase 之后的迭代器是严格不能使用的,使用就会报错,因为VS迭代器的底层不是原生指针,判断有所不同。
迭代器失效解决方案总结
1. 删除插入之后更新对应迭代器!(erase删除后会返回新的迭代器 ,按规则进行迭代就可以了 it = v1.erase(it)
2. 插入删除之后不使用迭代器

4 memcpy拷贝问题

我们创建一个string类的容器,来看看能不能正常运行:

void vector_test8() {
	vector<string> v1;
	v1.push_back("11111");
	v1.push_back("22222");
	v1.push_back("33333");
	v1.push_back("44444");
	v1.push_back("55555");

	print_vector(v1);
}

来看效果:
【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题),从零开始的C++生活,c++,java,开发语言,算法,linux,学习,蓝桥杯程序直接崩掉了,经过我们的调试,我们能打印出来正确的数据,但是走到程序最后的时候出现了错误,那么应该就是析构函数的问题了!
来画图分析一波:

  1. memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
  2. 如果拷贝的是自定义类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝
    【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题),从零开始的C++生活,c++,java,开发语言,算法,linux,学习,蓝桥杯

结论:如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃

那么怎么解决呢???非常简单:

		//扩容
		void reserve(size_t newcapacity) {
			//记录位置
			size_t n = _finish - _start;
			T* tmp = new T[newcapacity];
			//拷贝
			//memcpy(tmp, _start, size() * sizeof(T));
			for (size_t i = 0; i < size(); i++)
			{
				tmp[i] = _start[i];
			}
			delete[] _start;
			_start = tmp;
			_finish = _start + n;
			_end = _start + newcapacity;
			
		}

不使用memcpy函数不就可以了,然后我们使用简单粗暴的赋值拷贝,这样就不会发生浅拷贝问题了!!!文章来源地址https://www.toymoban.com/news/detail-845306.html

到了这里,关于【C++】vector问题解决(非法的间接寻址,迭代器失效 , memcpy拷贝问题)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【c++】list迭代器失效问题

    目录 一、list iterator的使用 二、list的迭代器失效         对于list的迭代器的用法,可以将它看做一个指针(实际要更加复杂)来使用,该指针指向list中的一个节点。         【注意】         (1)begin和end为正向迭代器,对迭代器执行++操作,迭代器向后移动         (2)r

    2024年01月23日
    浏览(40)
  • C++笔记之迭代器失效问题处理

    code review! 参考博文:C++STL迭代器失效的几种情况总结 对于 std::vector 来说,擦除(erase)元素会导致迭代器失效。具体而言

    2024年02月14日
    浏览(38)
  • 嵌入式:ARM间接寻址、变址寻址与多寄存器寻址

    寄存器间接寻址就是以寄存器中的值作为操作数的地址,而操作数本身存放在存储器中。例如以下指令: 第一条指令将以R1的值为地址的存储器中的数据传送到R0中。第二条指令将R0的值传送到以R1的值为地址的存储器中。 ARM的数据传送指令都是基于寄存器间接寻址,即通过

    2024年02月09日
    浏览(45)
  • 【C++庖丁解牛】STL之vector容器的介绍及使用 | vector迭代器的使用 | vector空间增长问题

    🍁你好,我是 RO-BERRY 📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 vector的文档介绍 vector是表示可变大小数组的序列容器。 就像数组一样,vector也采用的连续存储空间来存

    2024年03月14日
    浏览(75)
  • C++中vector迭代器

    迭代器 (iterator)是一种用于遍历数据集合的的对象。它提供了一种访问数据集合中元素的方式,而无需暴露数据集合内部的细节。使用迭代器,我们可以对数据集合中的每个元素进行处理,而无需将整个数据集合加载到内存中。这样可以节省内存空间,并且在处理大型数据

    2024年02月11日
    浏览(45)
  • C++:关于模拟实现vector和list中迭代器模块的理解

    本篇是关于 vector 和 list 的模拟实现中,关于迭代器模块的更进一步理解,以及在前文的基础上增加对于反向迭代器的实现和库函数的对比等 本篇是写于前面模拟实现的一段时间后,重新回头看迭代器的实现,尤其是在模板角度对 list 中迭代器封装的部分进行解析,希望可以

    2024年02月07日
    浏览(42)
  • 【C++】反向迭代器的模拟实现通用(可运用于vector,string,list等模拟容器)

    🌏博客主页: 主页 🔖系列专栏: C++ ❤️感谢大家点赞👍收藏⭐评论✍️ 😍期待与大家一起进步! 我们要写出一个通用的反向迭代器模拟而且在保证代码简介不繁琐的的情况下,一定程度上使用我们自己模拟的已经封装好的iterator迭代器可以简化许多步骤,首先我们要知

    2024年02月14日
    浏览(53)
  • [STL-list]介绍、与vector的对比、模拟实现的迭代器问题

     list的底层是 带头双向链表 结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。 与其他的序列式容器相比(array,vector,deque),list通常 在任意位置进行插入、移除元素的执行效率更好 list最大的缺陷是 不支持任意位

    2024年04月15日
    浏览(94)
  • 【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题

    更多算法例题链接: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题) 什么是迭代器(iterator) 迭代器(iterator)的定义: 迭代器是一种检查容器内元素并遍历元素的数据类型。 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。 容器

    2024年04月14日
    浏览(48)
  • 2.3 Vector 动态数组(迭代器)

    C++数据结构与算法 目录 1 C++自学精简教程 目录(必读) 2 VectorT 动态数组(模板语法) 1 熟悉迭代器设计模式; 2 实现数组的迭代器; 3 基于迭代器的容器遍历; 迭代器语法介绍 对迭代器的详细介绍参考 : 迭代器 iterator 范围for循环 删除容器的元素 remove erase 迭代器的能力 迭

    2024年02月10日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包