【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个小参数矩阵。...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...
Java数组Arrays操作全攻略
Arrays类的概述 Java中的Arrays类位于java.util包中,提供了一系列静态方法用于操作数组(如排序、搜索、填充、比较等)。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序(sort) 对数组进行升序…...
CppCon 2015 学习:REFLECTION TECHNIQUES IN C++
关于 Reflection(反射) 这个概念,总结一下: Reflection(反射)是什么? 反射是对类型的自我检查能力(Introspection) 可以查看类的成员变量、成员函数等信息。反射允许枚…...








