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

在这里插入图片描述
送给大家一句话:

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

vector问题解决

  • 1 前言
  • 2 迭代器区间拷贝
  • 3 迭代器失效问题
  • 4 memcpy拷贝问题

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;// 4cout << *it << endl;v1.insert(3, 40);cout << *it << endl;
}

这个执行的结果是:
在这里插入图片描述
迭代器的指向发生了改变,我们实现的迭代器的底层是指针,我们插入之后指针位置不变,而数组元素改变,自然会产生不一样的结果。这个问题看起来不严重,那我们再来看:

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;// 4cout << *it << endl;v1.insert(3, 40);cout << *it << endl;
}

在这里插入图片描述
为什么这里出现了乱码???我们代码和之前的区别是什么???一个进行了扩容,一个没进行扩容。扩容之后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);
}

现在出现了:
在这里插入图片描述
这个问题,问题的来源也很简单,我们迭代器在删除之后没有改变位置,但是_start的元素发生了改变,也就是相当于 it 向后移动了两次,为了避免这个情况我们可以:

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

这样就可以了:
在这里插入图片描述
需要注意的一点是,我们的操作是以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);
}

来看效果:
在这里插入图片描述程序直接崩掉了,经过我们的调试,我们能打印出来正确的数据,但是走到程序最后的时候出现了错误,那么应该就是析构函数的问题了!
来画图分析一波:

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

结论:如果对象中涉及到资源管理时,千万不能使用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函数不就可以了,然后我们使用简单粗暴的赋值拷贝,这样就不会发生浅拷贝问题了!!!

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

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

相关文章

牛市股票还会亏钱?--外观模式

1.1 牛市股票还会亏钱&#xff1f; 炒股&#xff0c;碰到熊市&#xff0c;亏得一塌糊涂。 "我们公司的人现在都在炒股票&#xff0c;其实大部分人都不太懂&#xff0c;就是因为现在股市行情很火&#xff0c;于是都在跟风呢&#xff01;" 刚入市的人&#xff0c;什么都…

Day84:服务攻防-端口协议桌面应用QQWPS等RCEhydra口令猜解未授权检测

目录 端口协议-口令爆破&未授权 弱口令爆破 FTP&#xff1a;文件传输协议 RDP&#xff1a;Windows远程桌面协议 SSH&#xff1a;Linux安全外壳协议 未授权案例(rsync) 桌面应用-QQ&WPS&Clash QQ RCE 漏洞复现 WPS RCE 漏洞复现 Clas* RCE 漏洞复现 知识点…

【攻防世界】ics-05

php://filter 伪协议查看源码 preg_replace 函数漏洞 1.获取网页源代码。多点点界面&#xff0c;发现点云平台设备维护中心时&#xff0c;页面发生变化。 /?pageindex 输入什么显示什么&#xff0c;有回显。 用php://filter读取网页源代码 ?pagephp://filter/readconvert.…

设计模式 --5观察者模式

观察者模式 观察者模式的优缺点 优点 当一个对象改变的时候 需要同时改变其他对象的相关动作的时候 &#xff0c;而且它不知道有多少具体的对象需要改变 应该考虑使用观察者模式 。观察者模式的工作就是解除耦合 让耦合双方都依赖与抽象 而不是具体 是的各自改变都不会影响另…

【文献分享】ALKEMIE:加速材料发现和设计的智能计算平台

题目&#xff1a;ALKEMIE: An intelligent computational platform for accelerating materials discovery and design 链接&#xff1a;DOI: 10.1016/j.commatsci.2020.110064 ALKEMIE&#xff1a;加速材料发现和设计的智能计算平台 摘要 通过传统的试错方式开发具有目标特性…

ChatGPT 的核心 GPT 模型:探究其生成式预训练变换架构的革新与应用潜力

GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型是一种深度学习模型&#xff0c;由OpenAI于2018年首次提出&#xff0c;并在随后的几年中不断迭代发展&#xff0c;包括GPT-2、GPT-3以及最新的GPT-4。GPT模型在自然语言处理&#xff08;NLP&#xff09;领域…

ssm基于HTML5的出租车管理系统论文

摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管理就很关键。因此出租车信息的管…

Linux云计算之Linux基础3——Linux基本认识操作

1、终端 终端(terminal)&#xff1a;人和系统交互的必要设备&#xff0c;人机交互最后一个界面&#xff08;包含独立的输入输出设备&#xff09; 物理终端(console)&#xff1a;直接接入本机器的键盘设备和显示器虚拟终端(tty)&#xff1a;通过软件方式虚拟实现的终端。它可以…

C++相关概念和易错语法(4)(构造函数、析构函数)

一、构造函数 1.实现的功能&#xff1a;实例化对象的时候默认自动调用&#xff0c;相当于初始化。 条件&#xff1a;在书写时要满足构造函数的规范&#xff08;函数名 类名&#xff0c;不写返回值&#xff0c;也没有返回值&#xff09;&#xff0c;可以用inline来修饰。 2.自…

4.6 offset指令,jmp short指令,far,dword ptr各种跳转指令

4.6 offset指令&#xff0c;jmp short指令&#xff0c;far&#xff0c;dword ptr各种跳转指令 可以修改IP&#xff0c;或同时修改CS和IP的指令统称为转移指令。概括的讲&#xff0c;转移指令就是可以控制CPU执行内存中某处代码的指令 1. 转移指令 1.1 8086CPU的转移行为有以…

按照指定的分隔符和次数从右侧开始分割字符串元素numpy.char.rsplit()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 按照指定的分隔符和次数 从右侧开始分割字符串元素 numpy.char.rsplit() [太阳]选择题 请问关于以下代码表述错误的选项是&#xff1f; import numpy as np a np.array([a b c, x,y,z, 1 2,…

HackTheBox-Mist

整体思路 端口扫描->Pluck CMS组件文件读取漏洞->文件上传获取shell->创建指向exe的快捷方式来提权-> 信息收集&端口利用 namp -sSVC 10.10.11.17目标只开放了80端口&#xff0c;将mist.htb加入到hosts文件后&#xff0c;访问mist.htb Pluck CMS文件读取 在…

3.6k star, 免费开源跨平台的数据库管理工具 dbgate

3.6k star, 免费开源跨平台的数据库管理工具 dbgate 分类 开源分享 项目名: dbgate -- 免费开源跨平台的数据库管理工具 Github 开源地址&#xff1a; GitHub - dbgate/dbgate: Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under…

Ps:合并到 HDR Pro

Ps菜单&#xff1a;文件/自动/合并到 HDR Pro Automate/Merge to HDR Pro 合并到 HDR Pro Merge to HDR Pro命令可以将同一场景的具有不同曝光度的多个图像合并起来&#xff0c;从而捕获单个 HDR 图像中的全部动态范围。 合并到 HDR Pro 命令分两步进行。 首先&#xff0c;需要…

Day82:服务攻防-开发组件安全Solr搜索Shiro身份Log4j日志本地CVE环境复现

目录 J2EE-组件Solr-本地demo&CVE 命令执行&#xff08;CVE-2019-17558&#xff09; 远程命令执行漏洞(CVE-2019-0193) Apache Solr 文件读取&SSRF (CVE-2021-27905) J2EE-组件Shiro-本地demo&CVE CVE_2016_4437 Shiro-550Shiro-721(RCE) CVE-2020-11989(身…

Emacs之解除comment-region绑定C-c C-c快捷键(一百三十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

【资源分享】Eclipse最新版本免费安装下载

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验&#xff0c;帮助大家尽早适应研究生生活&#xff0c;尽快了解科研的本质。祝一切顺利&#xff01;—…

成为不可替代的人,优秀到不能被忽视

一、资料描述 本套个人成长资料&#xff0c;大小30.89M&#xff0c;共有21个文件。 二、资料目录 00发刊词 成为不可替代的人.pdf 01累死你的不是工作&#xff0c;是错的职场价值观.pdf 02教你选好行业&#xff0c;远离裁员降薪.pdf 03如何选对公司&#xff0c;让高薪升值…

JavaScript中堆栈内存管理机制及其在深拷贝与浅拷贝场景中的应用与解析

一.堆栈的定义 1.栈是一种特殊的线性表。其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行。 结论&#xff1a;后进先出&#xff08;Last In First Out&#xff09;&#xff0c;简称为LIFO线性表。 栈的应用有&#xff1a;数制转换&#xff0c;语法词法分析&…

刷题之Leetcode704题(超级详细)

704. 二分查找 力扣题目链接(opens new window)https://leetcode.cn/problems/binary-search/ 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&am…