【C++/STL】vector(常见接口、模拟实现、迭代器失效)
🌈个人主页:秦jh_-CSDN博客
🔥 系列专栏: https://blog.csdn.net/qinjh_/category_12575764.html?spm=1001.2014.3001.5482
目录
简单使用
常见接口
find
insert
vector模板
模拟实现
尾插
构造
迭代器失效
使用memcpy拷贝问题
花括号列表初始化
完整代码
前言
💬 hello! 各位铁子们大家好哇。
今日更新了vector的相关内容
🎉 欢迎大家关注🔍点赞👍收藏⭐️留言📝
vector是表示可变大小数组的序列容器。
简单使用
vector接口的使用跟string差不多,功能很多都类似。
常见接口
注意end是指向最后一个数据的下一个位置。
find
find的使用需要包 <algorithm> 头文件
注意上面if语句的判断条件,找不到时,返回值是自己给的last,即上面的v.end()。
insert
insert还可以插入一段迭代区间
vector模板
vector<> 括号里可以是不同的类型,如上面的string,还可以是list,vector等。 如下图:
模拟实现
尾插
上方是错误的模拟。因为_start已经改变了,_finish-_start就不是原本的空间大小了。正确代码如下:
size_t size()
{return _finish - _start;
}T& operator[](size_t pos)
{assert(pos < size());return _start[pos];
}size_t capacity()
{return _endofstorage - _start;
}void push_back(const T& val) //传引用效率高
{if (_finish == _endofstorage){size_t old_size = size();size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;T* tmp = new T[newcapacity];memcpy(tmp, _start, size() * sizeof(T));delete[] _start;_start = tmp;_finish = tmp + old_size;_endofstorage = tmp + newcapacity;}*_finish = val;++_finish;
}
构造
在不写第三个函数的情况下,当我们想插入10个1构造时,会优先跟函数1匹配,因为他是模板, 而函数2的形参类型有size_t ,因此匹配度没模板的好。为了能够插入10个1进行构造,就需要函数3来进行匹配。没有函数3的情况下,(10u,1)和(10,'a')都会跟函数2匹配。
迭代器失效
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的 空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。
vector中,会引起其底层空间改变的操作,都有可能使迭代器失效,比如:resize、reserve、insert、assign、 push_back等。
迭代器失效解决办法:在使用前,对迭代器重新赋值即可。
插入发生错误的本质是迭代器失效,因为此时pos还指向旧空间,而旧空间已经被释放了。正确代码如下:
void insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);//如果扩容了就要更新pospos = _start + len;}iterator it = _finish - 1;while (it >= pos){*(it + 1) = *it;--it;}*pos = val;++_finish;}
另一个问题:
因为要扩容,此时it就是野指针了,要继续使用就得在外面重新更新。要解决这个问题就得在insert形参里面传引用,但是这会引发别的问题,库里面没有去解决这个问题,所以不要使用。
上方删除偶数的操作也是导致迭代器失效。erase删除pos位置元素后,pos位置之后的元素会往前搬移,如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是 没有元素的,那么pos就失效了。
库里面的解决方案如上图,erase删除后会返回删除元素的下一个位置,进行更新即可。
上图是修改后的代码。模拟实现的erase也要跟着修改 ,要有返回值,如下图:
使用memcpy拷贝问题
当不需要扩容时,可以正常运行。
如果扩容了,程序就崩了。问题出在memcpy上。
memcpy是按字节一个一个拷贝的。扩容时,开辟了新空间, 然后memcpy就把string拷贝到tmp上。接着delete时,会调用析构函数,此时string就没了,start指向的空间也被销毁了。再让start指向tmp的空间,而tmp空间里的string是浅拷贝,在刚才就没了。即memcpy使vector是深拷贝,但vector的对象string却是浅拷贝。
正确代码:
我们用循环进行赋值即可,赋值时每次都是深拷贝。
结论:如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。
void reserve(size_t n)
{if (n > capacity()){T* tmp = new T[n];size_t old_size = size();//memcpy(tmp, _start, size() * sizeof(T));for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];}delete[] _start;_start = tmp;_finish = tmp + old_size;_endofstorage = tmp + n;}
}
花括号列表初始化
库里面的vector支持用花括号初始化,其原理如下图:
即隐式类型转换,传引用时,注意临时对象具有常性,需要用const对象。
自己实现:
完整代码
#pragma once#include<assert.h>namespace qjh
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}vector(){}//v2(v1)vector(const vector<T>& v){reserve(v.capacity());for (auto& e : v){push_back(e);}}//vector<int> v1 ={1,2,3,4,5};vector(initializer_list<T> il){reserve(il.size()); for (auto& e : il){push_back(e);}}//类模板的成员函数可以是函数模板//迭代器区间构造,可以是vector的迭代器,也可以是其他容器template <class InputIterator>vector(InputIterator first, InputIterator last){ while (first != last){push_back(*first);++first;}}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}vector(int n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}void swap(vector<T> v){std::swap(_start, v._start); std::swap(_finish, v._finish); std::swap(_endofstorage, v._endofstorage); }//v1=v2vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){delete[] _start;_start = _finish = _endofstorage = nullptr;}size_t size() const{return _finish - _start;}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}size_t capacity() const{return _endofstorage - _start;}void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];size_t old_size = size();//memcpy(tmp, _start, size() * sizeof(T));for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];}delete[] _start;_start = tmp;_finish = tmp + old_size;_endofstorage = tmp + n;}}void resize(size_t n, const T& val = T()) //T()是匿名对象,自定义类型调用它的构造,内置类型也是,整形是0,字符是'\0',指针是空指针。{if (n > size()){reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}else{_finish = _start + n;}}void push_back(const T& val) //传引用效率高{/*if (_finish == _endofstorage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = val;++_finish;*/insert(end(), val);}void pop_back(){//assert(!empty());//--_finish;erase(--end());}bool empty(){return _start == _finish; }void insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);//如果扩容了就要更新pospos = _start + len;}iterator it = _finish - 1;while (it >= pos){*(it + 1) = *it;--it;}*pos = val;++_finish;}iterator erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;++it;}--_finish;return pos;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorage = nullptr;};template<class T>void print_vector(const vector<T>& v){for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//typename vector<T>::const_iterator it = v.begin(); //前面必须加typename 告诉编译器这是类型,//while (it != v.end())//{// cout << *it << " ";// ++it;//}//cout << endl;//for (auto e : v)//{// cout << e << " ";//}//cout << endl;}}
相关文章:

【C++/STL】vector(常见接口、模拟实现、迭代器失效)
🌈个人主页:秦jh_-CSDN博客🔥 系列专栏: https://blog.csdn.net/qinjh_/category_12575764.html?spm1001.2014.3001.5482 目录 简单使用 常见接口 find insert vector模板 模拟实现 尾插 构造 迭代器失效 使用memcpy拷贝问…...
Spring Boot Web 开发:MyBatis、数据库连接池、环境配置与 Lombok 全面解析
推荐一个AI网站,免费使用豆包AI模型,快去白嫖👉海鲸AI 1.0 MyBatis 概述 MyBatis 是一个优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 可以帮助我们将数据库操作抽象出来,使得我们的代码更加简洁…...

【UE5.1 多线程 异步】“Async Blueprints Extension”插件使用记录
目录 一、异步生成Actor示例 二、异步计算示例 参考视频 首先需要在商城中下载“Async Blueprints Extension”插件 一、异步生成Actor示例 2. 创建一个线程类,这里要指定父类为“LongAsyncTask”、“InfiniteAsyncTask”、“ShortAsyncTask”中的一个 在线程类…...

【已解决】在jupyter里运行torch.cuda.is_available(),显示True,在pycharm中运行却显示false。
文章目录 问题概述1、在Jupyter中GPU运行true2、在pycharm中GPU运行false3、个人解决方案仅供参考 问题概述 在jupyter里运行torch.cuda.is_available(),显示True,在pycharm中运行却显示false。原因在于jupyter 运行环境和pycharm 运行环境不同…...
Flutter 中的 Scrollbar 小部件:全面指南
Flutter 中的 Scrollbar 小部件:全面指南 在Flutter中,滚动条(Scrollbar)是一种常见的UI组件,用于提供对滚动内容的快速访问和控制。Scrollbar 小部件可以附加到任何可滚动的widget上,如ListView、GridVie…...

【华为】将eNSP导入CRT,并解决不能敲Tab问题
华为】将eNSP导入CRT,并解决不能敲Tab问题 eNSP导入CRT打开eNSP,新建一个拓扑右键启动查看串口号关联CRT成功界面 SecureCRT连接华为模拟器ensp,Tab键不能补全问题选择Options(选项)-- Global Options (全局选项&#…...

实验二 电子传输系统安全-进展2
上周任务完成情况(代码链接,所写文档等) 重新调通电子公文传输系统部署gmssl学习生成SM2证书学习gmssl中的CTLS实现将数据库从SqlServer迁移到Mysql调试Mysql驱动学习Bouncy Castle 代码链接 Mysql表设计 /* Navicat MySQL Data Transfer…...
JavaScript 获取 HTML 中特定父元素下的子元素
JavaScript 获取 HTML 中特定父元素下的子元素 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>查找子元素示例</title> </head> <body><div id"parent"><p&…...

等保服务是一次性服务吗?为什么?怎么理解?
我国等保政策已经严格落地执行,但还有不少企业对于等保服务不是很了解。例如有人问,等保服务是一次性服务吗?为什么?怎么理解?今天我们就来简单回答一下,仅供参考哈! 等保服务是一次性服务吗&…...

全网首发UNIAPP功能多的iapp后台源码
全网首发UNIAPP功能多的iapp后台源码,众所周知UN Dev Assist 后台是一款既不免费又不好用的后台今天直接分享。 搭建教程在里面了,自己查看。 源码下载:https://download.csdn.net/download/m0_66047725/89291994 更多资源下载:…...

【搜索方法推荐】高效信息检索方法和实用网站推荐
博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…...

面试被问到不懂的东西,是直接说不懂还是坚持狡辩一下?
大家好,我是瑶琴呀。 面试被问到不懂的东西,是直接说不懂还是坚持狡辩一下?这个问题可以转变一下,如果你顺利拿到 offer,公司安排的工作跟你之前的技术和经验不匹配,你还愿意干下去吗? 转变一…...
Flutter 中的 StatefulBuilder 小部件:全面指南
Flutter 中的 StatefulBuilder 小部件:全面指南 在Flutter中,StatefulBuilder是一个高效的小部件,它根据给定的构建函数来构建widget,并在组件树中只对需要重新构建的部分进行更新。这使得它在性能优化方面非常有用,特…...

mail发送接口API如何使用?怎么调用接口?
mail发送接口API的性能怎么样?邮件接口发信的技巧? 为了自动化和集成电子邮件功能到应用程序或系统中,开发人员可以使用各种邮件发送接口API。AokSend将介绍如何使用这些API来发送电子邮件,提高效率和灵活性。 mail发送接口API&…...

DOS学习-目录与文件应用操作经典案例-attrib
新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一.前言 二.使用 三.案例 一.前言 DOS系统中的attrib命令是一个用于显示或更改文件&#…...
STP简介
一、STP介绍 STP 即生成树协议(Spanning Tree Protocol)一种网络协议 STP 主要用于解决以太网中的环路问题。在具有冗余链路的网络环境中,环路可能导致广播风暴、重复帧等不良后果,严重影响网络性能和稳定性。STP 通过在交换机之…...

java调用科大讯飞在线语音合成API --内附完整项目
科大讯飞语音开放平台基础环境搭建 1.用户注册 注册科大讯飞开放平台账号 2.注册好后先创建一个自己的应用 创建完成后进入应用可以看到我们开发需要的三个参数:APPID,APISecret,APIKey 3.因为平台提供的SDK中只支持了简单的中英两种语言语音…...
Vuex 页面刷新数据丢失怎么解决
当Vuex中的数据在页面刷新后丢失时,这通常是因为Vuex的状态数据是保存在运行内存中的,页面刷新会导致Vue实例重新加载,进而Vuex中的数据被重置为初始状态。为了解决这个问题,可以采取以下几种方法: 1. 使用浏览器的本…...

如何使用Cloudways搭建WordPress网站
如今,搭建网站已经变得非常简单,这主要得益于开源的CMS建站系统的兴起。即使是不懂编程的人也能轻松搭建自己的网站,这些CMS系统提供了丰富的主题模板和插件,使用户可以通过简单的拖放和配置操作来建立自己的网站。 WordPress是目…...

Lora理解
Parameter-Efficient Fine-Tuning (PEFT) :节约开销的做法,fine-tune少量参数,而不是整个模型; Low-Rank Adaptation (LoRA) :是PEFT的一种;冻结原参数矩阵,只更新2个小参数矩阵。...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...