C++:STL:vector类常用函数介绍(附加部分重要函数模拟实现)

cplusplus.com/reference/vector/vector/icon-default.png?t=O83Ahttps://cplusplus.com/reference/vector/vector/

vector在实际中非常的重要,在实际中我们熟悉常见的接口就可以,有了string的基础,vector其实大体使用方法上二者是类似的:

这里我们先给出我们简单模拟实现时所用的成员函数:

private:iterator _start;iterator _finish;iterator _end_of_storage;

下文在介绍与string实现方式基本相同的地方,或者用法与string中相同函数基本一致的地方,均会直接以表格加实现代码的方式进行介绍,以便于我们重点介绍vector中我们需要了解的两个新知识:迭代器失效和更深层次的深浅拷贝问题。 

一,vector的定义

1.1(constructor)构造函数声明

cplusplus.com/reference/vector/vector/vector/icon-default.png?t=O83Ahttps://cplusplus.com/reference/vector/vector/vector/其中我们需要重点掌握的是以下几个构造函数:

以下是我们的简单实现代码:

template<class T>
class vector
{
public:	vector():_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){}template<class InputIterator>vector(InputIterator first, InputIterator last):_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){assert(first && last);InputIterator itor = first;for (; itor < last; itor++){push_back(*itor);}}vector(size_t n, const T& value = T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){resize(n, value);}vector(const vector<T>& v):_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){reserve(v.capacity());_finish = _start + v.size();for (size_t i = 0; i < size(); i++){(*this)[i] = v[i];}}vector<T>& operator=(vector<T> v){swap(this, v);return *this;}
}

其中的swap,push_back,resize以及reserve与string中的功能基本一样,我们后面在来介绍实现它们, 这里我们先不管它们如何实现。我们要重点说的是这里拷贝构造时遇到的深浅拷贝问题,这里先埋个伏笔。

1.2vector iterator 的使用

cplusplus.com/reference/vector/vector/begin/

cplusplus.com/reference/vector/vector/end/

 cplusplus.com/reference/vector/vector/rbegin/

 cplusplus.com/reference/vector/vector/rend/

typedef T* iterator;
typedef const T* const_iterator;
//iterator
iterator begin()
{return _start;
}iterator end()
{return _finish;
}const_iterator begin()const
{return _start;
}const_iterator end()const
{return _finish;
}

二,vector 空间增长问题 

cplusplus.com/reference/vector/vector/size/ 

cplusplus.com/reference/vector/vector/capacity/

cplusplus.com/reference/vector/vector/empty/

cplusplus.com/reference/vector/vector/resize/

cplusplus.com/reference/vector/vector/reserve/

 

size_t size()const
{return _finish - _start;
}size_t capacity()const
{return _end_of_storage - _start;
}
void resize(size_t n, const T& pos = T())
{while (size() < n){push_back(pos);}if (n <= size())_finish = _start + n;
}

接下来的reserve我们需要单独拎出来讲,先来看下我们在实现string的reserve时的模拟实现代码:

void string::reserve(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1] {'\0'};strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}
}

从string的模拟实现我们第一时间会想到去用memcpy来完成对n>capacity时的数据拷贝。当然,这种方法对于我们所有的内置类型都没有问题,比如vector<int>,vector<char>等等, 但如果是vector<string>这种成员元素是标准库类型的数据呢, 如果我们只是简单的去拷贝每一个字节,其实是对每一个元素的浅拷贝,就像这样:

void reserve(size_t n)
{if (n > capacity()){size_t oldsize = size();T* tmp = new T[n];if (_start){memcpy(tmp, _start, oldsize * sizeof(T));delete[] _start;}_start = tmp;_finish = _start + oldsize;_end_of_storage = _start + n;}
}

很明显的问题,接下来tmp中的string对象都会指向一块随即空间,也就是它们中的成员指针全部成了野指针。直接就会报错,解决方法其实也很简单,我们只需要改用for循环去拷贝数据即可,虽然会些许浪费时间,但是是我们简单模拟时一种较好的解决方法:

void reserve(size_t n)
{
if (n > capacity())
{size_t oldsize = size();T* tmp = new T[n];if (_start){for (size_t i = 0; i < oldsize; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + oldsize;_end_of_storage = _start + n;}
}

 除此之外,需要注意的点还有:

1.capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
2.reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代
价缺陷问题。
3.resize在开空间的同时还会进行初始化,影响size。

三,vector 增删查改 

 cplusplus.com/reference/vector/vector/reserve/

cplusplus.com/reference/vector/vector/push_back/

 cplusplus.com/reference/vector/vector/pop_back/

cplusplus.com/reference/algorithm/find/?kw=find

cplusplus.com/reference/vector/vector/insert/

cplusplus.com/reference/vector/vector/erase/

cplusplus.com/reference/vector/vector/swap/

 cplusplus.com/reference/vector/vector/operator[]/

//access
T& operator[](size_t i)
{assert(i < size());return _start[i];
}const T& operator[](size_t i)const
{assert(i < size());return _start[i];
}//modify
void push_back(T n)
{if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = n;_finish++;	
}void pop_back()
{assert(size());_finish--;
}void swap(vector<T>& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_sstorage);
}

 

TIPS:迭代器失效问题

注意:Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端。

这里我们借助insert与erase来介绍:

iterator insert(iterator pos, const T& x){assert(pos >= _start && pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator itor = _finish;while (itor >= pos){*(itor + 1) = *itor;--itor;}*pos = x;_finish++;return pos;
}iterator erase(iterator pos)
{assert(pos >= _start && pos < _finish);iterator itor = pos;while (itor < _finish - 1){*pos = *(pos + 1);}_finish--;return pos;
}

这里给出insert与erase主要是为了便于我们去对照vs与linux下实现代码的差异,下面我们来看第一种失效:

1.扩容引起的野指针:

我们来看下面一组例子:

void test_vector3()
{ELY::vector<int> v1;//ELY是我实现的vector所在的命名空间v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);//v1.push_back(4);for (auto e : v1){cout << e << " ";}cout << endl;int x;cin >> x;auto it = find(v1.begin(), v1.end(), x);if (it != v1.end()){v1.insert(it, 10 * x);cout << *it << endl;}for (auto e : v1){cout << e << " ";}cout << endl;
}

这串代码在vs下的运行结果如下图:

显然此时我们的it已经失效,因为扩容后,it如果没有更新,此时it指向的空间已经被释放了,导致it迭代器成了野指针,致使迭代器失效。

2.删除数据导致数据的挪动致使迭代器失效

void test_vector4(){std::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto e : v1){cout << e << " ";}cout << endl;int x;cin >> x;auto it = find(v1.begin(), v1.end(), x);if (it != v1.end()){v1.erase(it);cout << *it << endl;}}

 vs下面会直接报错:

g++ 下面正常运行:

再来看这样一组例子,删除数据中的所有偶数:

void test_vector4()
{std::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto e : v1){cout << e << " ";}cout << endl;auto it = v1.begin();while (it != v1.end()){if (*it % 2 == 0)v1.erase(it);++it;}for (auto i : v1){cout << i << ' ';}cout << endl;
}

vs下面还是直接报错:

 

g++上面运行:

这里直接端错误。

换一组数据我们会发现偶数并没有被删干净。

///

从上述三个例子中可以看到:SGI STL中,迭代器失效后,代码并不一定会崩溃,但是运行
结果肯定不对,如果it不在begin和end范围内,肯定会崩溃的。

所以我们在使用迭代器的时候,一定要注意迭代器失效的问题,要及时更新我们的迭代器。

迭代器失效解决办法:在使用前,对迭代器重新赋值即可。

 

 

 

 

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

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

相关文章

ScriptableObject基本使用

使用方法 自定义类继承ScriptableObject 可以在类内部增加数据或者数据类&#xff0c;一般用于配置 注意事项 给继承ScriptableObject的类增加CreateAssetMenu特性。 CreateAssetMenu一般默认三个参数 第一个参数是父目录 第二个参数是父目录的子选项 第三个参数是可以…

多态(二)

1.多态的原理 虚函数表 class Base { public:virtual void Func1(){cout << "Func1()" << endl;} private:int _b 1; };b对象是8bytes&#xff0c;除了_b成员&#xff0c;还多一个__vfptr放在对象的前面(注意有些 平台可能会放到对象的最后面&#xf…

微信小程序启动不起来,报错凡是以~/包名/*.js路径的文件,都找不到,试过网上一切方法,最终居然这么解决的,【避坑】命运的齿轮开始转动

app.json "resolveAlias": {"~/*": "/*"},文件代码也没有问题&#xff0c;网上的方法试过来了&#xff0c;大模型AI也问过遍&#xff0c;熬夜到凌晨2点半&#xff0c;最不可思议的是居然是因为微信开发者工具版本的问题&#xff0c;我真的是笑死…

量化之一:均值回归策略

文章目录 均值回归策略理论基础数学公式 关键指标简单移动平均线&#xff08;SMA&#xff09;标准差Z-Score 交易信号实际应用优缺点分析优点缺点 结论 实践backtrader参数&#xff1a;正常情况&#xff1a;异常情况&#xff1a; 均值回归策略 均值回归&#xff08;Mean Rever…

JAVA-数据结构-排序

1.直接插入排序 1.原理&#xff1a;和玩扑克牌一样&#xff0c;从左边第二个牌开始&#xff0c;选中这个&#xff0c;和前面的所有牌比较&#xff0c;插在合适的位置 public static void insertsort(int[] arr){//直接插入排序for (int i 1; i < arr.length; i) {//此循环…

STM32 GPIO

GPIO&#xff08;通用输入输出口&#xff0c;General Purpose Input Output&#xff09;接口的功能是让嵌入式处理器能够通过软件灵活地读出或控制单个物理引脚上的高、低电平&#xff0c;实现内核和外部系统之间的信息交换。 GPIO是嵌入式处理器使用最多的外设&#xff0c;能够…

甲虫身体图像分割系统源码&数据集分享

甲虫身体图像分割系统源码&#xff06;数据集分享 [yolov8-seg-EfficientRepBiPAN&#xff06;yolov8-seg-C2f-FocusedLinearAttention等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challen…

毕设开源 大数据电影数据分析与可视化系统(源码+论文)

文章目录 0 前言1 项目运行效果2 设计概要3 最后 0 前言 &#x1f525;这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师…

简单粗暴理解GNN、GCN、GAT

GNN 思想&#xff1a;近朱者赤近墨者黑 GNN的流程&#xff1a; 聚合&#xff08;把邻居的信息贴到自己身上来&#xff0c;作为它自己特征的补足&#xff09;更新循环&#xff08;为什么要多次&#xff1f;看以下例子&#xff09; GNN能干嘛&#xff1f; 1.结点分类&#xf…

【多线程】多线程(12):多线程环境下使用哈希表

【多线程环境下使用哈希表&#xff08;重点掌握&#xff09;】 可以使用类&#xff1a;“ConcurrentHashMap” ★ConcurrentHashMap对比HashMap和Hashtable的优化点 1.优化了锁的粒度【最核心】 //Hashtable的加锁&#xff0c;就是直接给put&#xff0c;get等方法加上synch…

【网络协议】TCP协议常用机制——延迟应答、捎带应答、面向字节流、异常处理,保姆级详解,建议收藏

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;计算机网络那些事 前几篇文章&#xff0c;博主带大家梳理了一下TCP协议的几个核心机制&#xff0c;比如保证可靠性的 确认应答、超时重传 机制&#xff0c;和提高传输效率的 滑动窗口及其相关优化机…

Qt实现Halcon窗口显示当前图片坐标

一、前言 Halcon加载图片的窗口&#xff0c;不仅能放大和缩小图片&#xff0c;还可以按住Ctrl键显示鼠标下的灰度值&#xff0c;这种方式很方便我们分析缺陷的灰度和对比度。 二、实现方式 ① 创建显示坐标和灰度的widget窗口 下图的是widget部件&#xff0c;使用了4个label控…

常说的风险评估,那么「基于风险的测试 (RBT)」如何测试?

基于风险的测试 &#xff08;RBT&#xff09; 是一种测试方法&#xff0c;它根据风险的概率和影响确定测试活动的优先级。它涉及在潜在问题发生之前识别它们&#xff0c;并将资源分配给风险最高的测试区域。 在 RBT 中&#xff0c;“风险”是指缺陷的可能性及其对系统运行或业…

DS线性表之单链表的讲解和实现(2)

文章目录 前言一、链表的概念二、链表的分类三、链表的结构四、前置知识准备五、单链表的模拟实现定义头节点初始化单链表销毁单链表打印单链表申请节点头插数据尾插数据头删数据尾删数据查询数据在pos位置之后插入数据删除pos位置之后的数据 总结 前言 本篇的单链表完全来说是…

架设传奇SF时提示此服务器满员,GEE引擎点开始游戏弹出服务器满员的解决方法

昨天一个朋友在架设GEE的传奇服务端时遇到一个奇怪的问题&#xff0c;就是在服务器外网架设时&#xff0c;建好角色点开始游戏提示此服务器满员&#xff0c;这个问题一般比较少见&#xff0c;而且出现的话一般都是GEE引擎的版本。 他折腾了半天&#xff0c;一直没进游戏&#x…

Apache Linkis + OceanBase:如何提升数据分析效率

计算中间件 Apache Linkis 构建了一个计算中间件层&#xff0c;以实现上层应用程序和底层数据引擎之间的连接、治理和编排。目前&#xff0c;已经支持通过数据源的功能&#xff0c;实现用户通过Linkis 对接并使用 OceanBase数据库。 本文详细阐述了在 Apache Linkis v1.3.2中&a…

VGG16模型实现MNIST图像分类

MNIST图像数据集 MNIST&#xff08;Modified National Institute of Standards and Technology&#xff09;是一个经典的机器学习数据集&#xff0c;常用于训练和测试图像处理和机器学习算法&#xff0c;特别是在数字识别领域。该数据集包含了大约 7 万张手写数字图片&#xf…

线性代数在大一计算机课程中的重要性

线性代数在大一计算机课程中的重要性 线性代数是一门研究向量空间、矩阵运算和线性变换的数学学科&#xff0c;在计算机科学中有着广泛的应用。大一的计算机课程中&#xff0c;线性代数的学习为学生们掌握许多计算机领域的关键概念打下了坚实的基础。本文将介绍线性代数的基本…

高考技术——pandas使用

百家讲坛&#xff0c;谈论古今&#xff0c;今天我们不聊别的&#xff0c;我们来聊一聊中国的国宝——大熊猫&#xff08;bushi&#xff09; 好好&#xff0c;言归正传&#xff0c;我们今天来讲pandas import pandas as pd 申明无需多言&#xff0c;高考主要考察Series和Data…

Milvus向量数据库管理工具[Attu]实践

Attu是一款专为Milvus向量数据库打造的开源数据库管理工具&#xff0c;提供了便捷的图形化界面&#xff0c;极大地简化了对Milvus数据库的操作与管理流程。阿里云Milvus集成了Attu&#xff0c;以便更加高效地管理数据库、集合&#xff08;Collection&#xff09;、索引&#xf…