C++ STL容器之vector的使用及复现

vector

1. 序列式容器

vector、list、deque、forward_list(C++11)等STL容器,其底层为线性序列的数据结构,里面存储的是元素本身,这样的容器被统称为序列式容器。

2. vector容器

vector使用模板作为参数,所以在使用的时候必须将模板实例化,否则编译器无法识别你写的对象是什么类型。

Vector1

Vector2

必须实例化模板

C++11 支持了一种特殊的赋值方式,编译器是通过把{}识别成了std::initializer_list类模板来实现的。

Vector3

这种赋值方式对一般的内置类型也适用:

Vector4

但这种赋值方式使用不多(因为太不c++了)

3. vector的成员函数

3.1 vector的成员函数介绍

1. vector的构造函数

函数声明功能介绍
vector< T > v()构造一个空的vector
vector< T > v(n,val)构造一个内容为n个val的vector
vector< T > v (v1.iterator1(),v1.iterator2())构造一个从v1的iterator1到iterator2的vector
vector< T >v(v1)拷贝构造一个v1的vector

2. vector的迭代器

函数名功能介绍
beginendbegin:首元素的位置;end:下一个元素的位置
rbeginrendc指const,cbegin和cend指向的内容不能修改
cbegincend反向迭代器,rbegin从end开始,rend从begin开始,其++和–的方向相反
crbegincrend与前一个功能相同,但指向的内容不能修改

3.vector的容量与元素访问

函数名函数声明功能介绍
sizesize_type size() const返回vector中有效元素个数
resizevoid resize (size_type n, value_type val = value_type())如果n小于size,则缩小vector到n个有效元素(大于n的位置的元素被删除);如果n大于size,则增大vector到n,大于size的部分用val填补(无参则补val的默认构造)
capacitysize_type capacity() const返回vector开设的空间的元素大小(注意是以元素而不是字节计数)
reservevoid reserve (size_type n)将vector的空间增大到n个有效元素的大小,如果n小于size则无效
operator[]reference operator[] (size_type n)返回指向vector第n个位置的迭代器

4. vector的修改

函数名函数声明功能介绍
push_backvoid push_back (const value_type& val)尾插元素(vector只支持单个数据的尾插)
pop_backvoid pop_back()尾删元素
insertiterator insert (iterator position, const value_type& val)
void insert (iterator position, size_type n, const value_type& val)
在pos位置插入一个元素
在pos位置插入n个元素
eraseiterator erase (iterator position)
iterator erase (iterator first, iterator last)
删除pos位置的元素
删除first位置到last位置的元素

3.2 vector的resize

resize在不传val参数时会使用缺省值,但是对于不同类型的数据,其缺省值也应用不同的值,resize是怎么实现的呢?

void resize (size_type n, value_type val = value_type())

resize通过调用实例化的模板的默认构造来实现传递不同的缺省值,但如果模板实例化的类型不是自定义类型而是内置类型呢?

实际上,c++的内置类型也有默认构造:

int  main()
{int i = int();float f = float();double d = double();char c = char();return  0;
}

Vector5

这使得内置类型和自定义类型都能使用模板的缺省值传参。

3.3 二维vector与二维数组的异同

创建一个二维数组和一个二维vector,它们的访问方式都是一模一样的:

int n[i][j];
vector<vector<int>> n;
n[i][j]

但它们实现的原理不同:

Vector6

二维数组的访问的底层是靠指针的解引用实现的,而二维vector的访问的底层是通过函数调用实现的

4. 复现vector

4.1 填充构造函数和范围构造函数的冲突

vector实例化为int类型时,使用这种初始化方式会导致以下两种构造函数都使用,但第一种更匹配。导致错误调用了本不该调用的构造函数。

Vector7

Vector8

两个构造函数的重载冲突造成了编译错误。

这种错误类型只针对int类型,size_t类型都不会有相同的冲突。因此解决方法很简单,只需要专门为 int 类型写一个重载的 fill 构造函数即可:

Vector9

4.2 扩容导致的隐含浅拷贝问题

vector的reserve()在扩容时,不能使用memcpy()交换新旧空间的指针,因为当vector实例化为string类时,string会浅拷贝。在释放旧的空间后,新的空间也会一同释放,造成越界访问的错误。

Vector10

解决方法很简单,只需要把旧空间的内容一个一个拷贝到新的空间即可:

Vector11

4.3 扩容和删除导致迭代器失效问题

迭代器失效是迭代器指向的元素或空间发生了变化,导致迭代器不再指向预期的元素或变得无效。

扩容:

insert()函数在一般的确定类型的数据结构中,pos一般都是一个整型,但由于vector支持多类型的数据,所以vector的pos是一个迭代器类型(iterator),而iterator是一个模板的指针。即pos也是一个模板的指针,这使得在扩容等操作时,如果没有对pos以iterator的形式操作,导致它失效。

当扩容时,底层调用 malloc(),当前方没有足够的空间原地扩容时,malloc() 会另找一块足够大的空间,将原数据拷贝过去,那么此时的 pos 是一个模板指针类型,如果不对其进行更新,就会变成野指针。

Vector12

删除:

vector的 erase() 在 STL 中不允许迭代器在调用函数后继续使用迭代器,因为在以下场景会产生问题。

这是一个删除 vector<int> 类型里的所有偶数的代码:

int main()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);vector<int>::iterator it = v1.begin();while (it != v1.end()){if (*it % 2 == 0){v1.erase(it);}++it;}for (auto e : v1){std::cout << e << " ";}return 0;
}

Vector13

它能够正常运行,但当 vector 里的数据有两个偶数相连,或两个相连的偶数在最后的位置时:

	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);
//或
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(6);

Vector14

两种情况:一种是结果有问题,而另一种直接造成了程序的崩溃

查阅stl库里的vecotr的erase()函数可以看到,这个函数有一个返回值,并且它的返回值是迭代器

Vector15

所以官方实际上是通过直接更新迭代器来避开这个问题的,重构代码和删除的写法如下:

Vector16

4.4 完整代码

#pragma once
#include<iostream>
#include<assert.h>namespace myvector
{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;}//defaultvector(){}//fillvector(size_t n, const T& val = T()){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}vector(int n, const T& val = T()){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}//rangetemplate<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++_finish;}}//initializer list  c++11支持vector(std::initializer_list<T> il){reserve(il.size());for (auto& e : il){push_back(e);}}//copyvector(const T& v){reserve(v.size());for (auto& e : v){push_back(e);}}~vector(){delete[] _start;_start = _finish = _endofstorage = nullptr;}void reserve(size_t n){if(n>capacity()){T* temp = new T[n];size_t old_size = size();//使用memcpy会引发隐含浅拷贝for (size_t i = 0; i < old_size; i++){temp[i] = _start[i];}delete[] _start;_start = temp;_finish =temp+old_size;_endofstorage = temp + n;}}void push_back(const T& val){insert(end(), val);}void pop_back(){erase(end() - 1);}void insert(iterator pos, const T& val)//vector只支持单数据插入{assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _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;//返回删除的下一个(更新后)的位置}void swap(vector<T>& v){std::swap(_start,v._start);std::swap(_finish,v._finish);std::swap(_endofstorage,v._endofstorage);}size_t capacity() const{return _endofstorage - _start;}size_t size() const{return _finish - _start;}void resize(size_t n, const T& val = T()){if (n > size()){reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}else{_finish = _start + n;}}bool empty(){return _start == _finish;}vector<T>& operator=(vector<T> v){swap(v);return  *this;}T& operator[](size_t pos){assert(pos <= size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos <= size());return _start[pos];}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorage = nullptr;};
}

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

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

相关文章

算法15(力扣347)——前k个高频元素

1、问题 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 2、示例 &#xff08;1&#xff09; 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2] &#xff08;2&#xff09; 输入: nums [1], k 1 输出: [1…

项目质量管理体系及保证措施

项目质量管理体系的核心是建立标准化流程、强化全员参与意识、实施动态监控机制。其中&#xff0c;标准化流程是质量管理的基石。例如&#xff0c;某全球500强企业通过引入ISO 9001体系&#xff0c;将项目缺陷率降低了37%。标准化流程不仅能明确各环节的质量要求&#xff0c;还…

2025web寒假作业二

一、整体功能概述 该代码构建了一个简单的后台管理系统界面&#xff0c;主要包含左侧导航栏和右侧内容区域。左侧导航栏有 logo、管理员头像、导航菜单和安全退出按钮&#xff1b;右侧内容区域包括页头、用户信息管理内容&#xff08;含搜索框和用户数据表格&#xff09;以及页…

服务器ip被反垃圾列为黑名单

查询 BarracudaCentral.org - Technical Insight for Security Pros https://multirbl.valli.org/lookup/ 大概写&#xff1a;我不知道这个IP在我使用之前已被列入Barracuda信誉阻止列表&#xff08;BRBL&#xff09;。我不知道它之前列出的原因&#xff0c;但服务器现在有了…

2025影视泛目录站群程序设计_源码二次开发新版本无缓存刷新不变实现原理

1. 引言 本设站群程序计书旨在详细阐述苹果CMS泛目录的创新设计与实现&#xff0c;介绍无缓存刷新技术、数据统一化、局部URL控制及性能优化等核心功能&#xff0c;以提升网站访问速度和用户体验。 2. 技术概述 2.1 无缓存刷新技术 功能特点&#xff1a; 内容不变性&#x…

激活函数 05 ——Swish

Swish背景 发展阶段典型函数主要特性局限性早期阶段Sigmoid/Tanh平滑可导&#xff0c;输出有界梯度消失问题现代阶段ReLU计算高效&#xff0c;缓解梯度消失神经元死亡现象改进阶段LeakyReLU改善负区间响应参数敏感性新星阶段Swish/GELU自适应非线性计算复杂度略高 Swish激活函…

Tria Technologies RFSoC 平台 - 入门指南

Tria Technologies RFSoC 平台 - 入门指南 适用于 RFSoC Gen-3 的宽带毫米波无线电开发平台 该平台将 Otava 和 Avnet 联合开发的 Otava DTRX2 双收发器毫米波无线电卡与 AMD Xilinx Zynq UltraScale ™ RFSoC ZCU208 评估套件相结合。 5G 毫米波相控阵天线模块开发平台 …

Win11下搭建Kafka环境

目录 一、环境准备 二、安装JDK 1、下载JDK 2、配置环境变量 3、验证 三、安装zookeeper 1、下载Zookeeper安装包 2、配置环境变量 3、修改配置文件zoo.cfg 4、启动Zookeeper服务 4.1 启动Zookeeper客户端验证 4.2 启动客户端 四、安装Kafka 1、下载Kafka安装包…

白嫖RTX 4090?Stable Diffusion:如何给线稿人物快速上色?

大家都知道&#xff0c;在设计的初期&#xff0c;我们通常会先绘制草图&#xff0c;然后再进行上色处理&#xff0c;最终才开始进行最终的设计工作。在这个上色的过程中&#xff0c;配色是至关重要的一环。这不仅方便了内部同事的评审&#xff0c;也让产品方和客户可以直观地了…

从大规模恶意攻击 DeepSeek 事件看 AI 创新隐忧:安全可观测体系建设刻不容缓

作者&#xff1a;羿莉&#xff08;萧羿&#xff09; 全球出圈的中国大模型 DeepSeek 作为一款革命性的大型语言模型&#xff0c;以其卓越的自然语言处理能力和创新性成本控制引领行业前沿。该模型不仅在性能上媲美 OpenAI-o1&#xff0c;而且在推理模型的成本优化上实现了突破…

AMD 8845HS 780M核显部署本地deepseek大模型的性能

测试了一下笔记本电脑AMD 8845HS的780M核显是否能本地部署deepseek大模型。 测试软件环境&#xff1a;LM Studio 0.3.9 、Windows 11 24H2 硬件&#xff1a;荣耀X16笔记本 CPU&#xff1a;AMD 8845HS 显卡&#xff1a;780M核显&#xff0c;显存为共享内存自动分配模式&…

利用二分法进行 SQL 盲注

什么是sql注入&#xff1f; SQL 注入&#xff08;SQL Injection&#xff09;是一种常见的 Web 安全漏洞&#xff0c;攻击者可以通过构造恶意 SQL 语句来访问数据库中的敏感信息。在某些情况下&#xff0c;服务器不会直接返回查询结果&#xff0c;而是通过布尔值&#xff08;Tr…

《深度学习》——pytorch框架及项目

文章目录 pytorch特点基本概念 项目项目实现导入所需库下载训练数据和测试数据对训练和测试样本进行分批次展示手写图片判断pytorch是否支持GPU定义神经网络模型定义训练函数定义测试函数创建交叉熵损失函数和优化器通过多轮训练降低损失值得到最终结果注意 pytorch PyTorch 是…

【批量获取图片信息】批量获取图片尺寸、海拔、分辨率、GPS经纬度、面积、位深度、等图片属性里的详细信息,提取出来后导出表格,基于WPF的详细解决方案

摄影工作室通常会有大量的图片素材&#xff0c;在进行图片整理和分类时&#xff0c;需要知道每张图片的尺寸、分辨率、GPS 经纬度&#xff08;如果拍摄时记录了&#xff09;等信息&#xff0c;以便更好地管理图片资源&#xff0c;比如根据图片尺寸和分辨率决定哪些图片适合用于…

windows生成SSL的PFX格式证书

生成crt证书: 安装openssl winget install -e --id FireDaemon.OpenSSL 生成cert openssl req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -subj "/CN=localhost" 转换pfx openssl pkcs12 -export -out certificate.pfx…

UnityShader学习笔记——高级纹理

——内容源自唐老狮的shader课程 目录 1.立方体纹理 1.1.概念 1.2.用处 1.3.如何采样 1.4.优缺点 2.天空盒 2.1.概念 2.2.优点 2.3.设置 3.动态生成立方体纹理 3.1.原因 3.2.实现 3.3.代码运行中生成 4.反射 4.1.原理 4.2.补充知识 5.折射 5.1.原理 5.2.菲涅…

IBM服务器刀箱Blade安装Hyper-V Server 2019 操作系统

案例:刀箱某一blade,例如 blade 5 安装 Hyper-V Server 2019 操作系统(安装进硬盘) 刀箱USB插入安装系统U盘,登录192.168... IBM BlandeCenter Restart Blande 5,如果Restart 没反应,那就 Power Off Blade 然后再 Power On 重启后进入BIOS界面设置usb存储为开机启动项 …

C++20新特性

作者&#xff1a;billy 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 前言 C20 是 C 标准中的一个重要版本&#xff0c;引入了许多新特性和改进&#xff0c;包括模块&#xff08;Modules&#xff09;、协程…

WPS如何接入DeepSeek(通过JS宏调用)

WPS如何接入DeepSeek 一、文本扩写二、校对三、翻译 本文介绍如何通过 WPS JS宏调用 DeepSeek 大模型&#xff0c;实现自动化文本扩写、校对和翻译等功能。 一、文本扩写 1、随便打开一个word文档&#xff0c;点击工具栏“工具”。 2、点击“开发工具”。 3、点击“查看代码”…

【SQL server】关于SQL server彻底的卸载删除。

1.未彻底卸载删除SQL Server会出现的问题 如果没有彻底删除之前的SQL server&#xff0c;就可能会出现这个 当要安装新的实例的时候因为之前安装过sql server没有删除干净而导致下图问题&#xff0c;说实例名已经存在。 2.首先要先关闭服务 “开始R”可以快速进入运行&#…