【STL容器】vector

文章目录

  • 前言
  • vector
    • 1.1 vector的定义
    • 1.2 vector的迭代器
    • 1.3 vector的元素操作
      • 1.3.1 Member function
      • 1.3.2 capacity
      • 1.3.3 modify
    • 1.4 vector的优缺点


前言

vector是STL的容器,它提供了动态数组的功能。
注:文章出现的代码并非STL库里的源码,只是对源码的简单化处理


vector

1.1 vector的定义

vector的成员变量是3个迭代器,用来管理一段线性连续空间

具体如下图:

在这里插入图片描述

1.2 vector的迭代器

vector的迭代器是指针,且属于随机迭代器
vector所管理的是一个连续线性的空间,因此无论类型如何,普通的指针就可以很好的解决问题。

注:
随机迭代器,在支持双向移动的基础上,支持前后位置的比较、随机存取、直接移动n个距离。
在这里插入图片描述

模拟如下:

template<class T>
class vector
{
public:typedef T* iterator;typedef const T* const_iterator;private:iterator _start;iterator _finish;iterator _end_of_storage;
};

1.3 vector的元素操作

1.3.1 Member function

构造函数
在这里插入图片描述
这里我们先不管空间配置器(allocator),以及explicit关键字.
简化上面的3个红框的部分

//1.
vector();
//2.
vector(size_t n, const T& t = T());
//3.
template<class InputIterator>
vector(InputIterator first, InputIterator last);

简化后1和2就容易理解了,但可能对于3还有些困惑
它的使用如下:
在这里插入图片描述
简化实现如下:

template<class InputIterator>
vector(InputIterator first, InputIterator last)
{while(first != last){this->push_back(*first);++first;}
}

赋值运算符重载
对于赋值运算符重载函数,有一种现代的写法

//现代写法
void swap(vector<T>& tmp)
{std::swap(_start, tmp._start);std::swap(_finish, tmp._finish);std::swap(_end_of_storage, tmp._end_of_storage);
}
vector<T>& operator=(vector<T> tmp)
{swap(tmp);return *this;
}
//传统写法
vector<T>& operator=(const vector<T>& v)
{if(this != &v){clear();detele[] _start;iterator tmp = new T[v.capacity()]_start = tmp;_finish = tmp + v.size();_end_of_storage = tmp + v.capacity();for(size_t i = 0; i < v.size(); i++){_start[i] = v[i];}}return *this;
}

我们浅浅分析一下,
传统的赋值逻辑是先将原空间删除,再开辟一个新空间,然后将数据慢慢拷贝过去。
现代的赋值逻辑,operator=的形参tmp不是引用,是通过拷贝构造得到的局部对象,然后通过swap(), 将tmp与this的数据进行交换,这样this指向了它想要的空间,而tmp指向了旧空间,又因为tmp是局部对象,等operator=函数结束时,tmp会自动调用析构函数,释放tmp指向的空间,也就是原来的旧空间。
相比原来的旧空间,不但减少了代码,更减少了错误。

注:有些人在用传统方法写赋值运算符重载时,会犯一个严重的错误,就是使用memcpy对原来的数据进行拷贝。

错误:memcpy(_start, v._start, sizeof(T)*v.size());
正确:for(size_t i = 0; i < v.size(); i++)
{ _start[i] = v[i]; }

这是比较典型的值拷贝问题,如果vector存储的类型T是内置类型,没什么事,但如果是自定义类型, 指针则会出错
在这里插入图片描述


1.3.2 capacity

在这里插入图片描述

上面的问题也容易出现在reserve
reserve()
作用:开辟空间到n,但如果n < capacity,则不会变。总结一句,只接受变大。

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

resize
强制将size改到n

  1. 如果sz > n,则删除数据
  2. 如果sz < n,则扩容,并填入t
void resize(size_t n, const T t = T()){if (n < size()){_finish = _start + n;}else{if (n > capacity()) reserve(n);for (iterator i = _finish; i < _start + n; i++){*i = t;}_finish = _start + n;}}

1.3.3 modify

在这里插入图片描述

这里介绍一些insert和erase

erase()
在这里插入图片描述
模拟:

iterator erase(iterator pos)
{assert(pos >= _start && pos < _finish);iterator it = pos;while (it != _finish){*it = *(it + 1);++it;}--_finish;return pos;
}
iterator erase(iterator first, iterator last)
{assert(first >= _start && first < _finish);assert(last >= _start && last <= _finish);assert(first<= last);iterator it = first;while(last != _finish){*it = *last;++it, ++last;	}_finish = it;return it;
}

insert
在这里插入图片描述

void insert(iterator pos, const T& t)
{assert(pos >= _start && pos <= _finish);if (_finish == _endofstorage){size_t n = capacity() == 0 ? 4 : 2 * capacity();reserve(n);}iterator end = _finish;while (end > pos){*end = *(end - 1);--end;}*pos = t;_finish++;
}

注:在对容器的修改,一定要注意迭代器失效的问题
以erase为例
在这里插入图片描述
在某些平台,上面的代码是会报错的,比如vs编译器。
逻辑是这样的,v.erase(it)将it所对应位置的数据删除,删除后it就不应该具有再次访问的权利,因为这有非法访问的可能。对于vector这种连续的空间,删除数据后,后面的数据会往前补上。但如果是像list的这样的链表,删除后,iterator指向的将是一块已经被释放的空间。这很明显不对。因此,编译器决定将这样的迭代器判定为失效。但并不是所有的编译器都会这样做。比如linux下的g++对于上面的代码就不会报错。


1.4 vector的优缺点

std::vector 是 C++ STL 提供的一个非常有用的动态数组容器,它有许多优点和一些局限性,以下是其主要优缺点:

优点:

  1. 快速随机访问:由于元素在内存中是连续存储的,vector 允许在常量时间内进行随机访问,这意味着可以通过索引快速访问任何元素。

  2. 动态大小vector 允许在运行时动态增加或减少其大小,这使得它非常适合需要动态分配内存的情况。

  3. 自动内存管理vector 会自动处理内存的分配和释放,无需手动管理内存,这可以减少内存泄漏和其他与手动内存管理相关的问题。

  4. 迭代器支持vector 支持迭代器,你可以使用迭代器来遍历容器中的元素,执行各种操作,如查找、排序等。

  5. 元素复制和移动vector 可以容纳各种数据类型,包括内置类型和用户自定义类型。它会在容器内部复制或移动元素的副本,而不影响原始对象。

缺点:

  1. 插入和删除效率较低:在 vector 中插入或删除元素涉及到移动其他元素,因此插入和删除操作的效率较低。如果需要频繁的插入和删除操作,可能有更适合的容器,如 std::liststd::deque

  2. 内存浪费vector 会预留一定的内存容量以容纳更多的元素,这可能导致内存浪费,特别是当你不确定容器的最终大小时。可以使用 reserve() 来手动管理内存分配,但仍可能存在浪费。

  3. 固定的增长策略vector 的内部实现通常采用固定的增长策略,即每次扩容都会分配一块更大的内存并复制元素。这可能导致一些性能问题,特别是在大规模元素插入时。如果需要更高效的动态数组,可以考虑使用 std::deque 或其他容器。

  4. 不适用于复杂的插入操作:如果需要在中间或开头插入元素并保持高效性能,vector 可能不是最佳选择,因为插入元素后需要移动大量元素。

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

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

相关文章

包管理工具--》发布一个自己的npm包

包管理工具系列文章目录 一、包管理工具--》npm的配置及使用&#xff08;一&#xff09; 二、包管理工具--》npm的配置及使用&#xff08;二&#xff09; 三、包管理工具--》发布一个自己的npm包 四、包管理工具--》yarn的配置及使用 五、包管理工具--》其他包管理器之cnpm…

花见Live Wallpaper Themes 4K Pro for mac(4k视频壁纸)

如果你希望让自己的Mac桌面焕发活力&#xff0c;那么Live Wallpaper & Themes 4K Pro正是一款值得尝试的软件。它提供了丰富的超高清4K动态壁纸和主题&#xff0c;可以让你轻松打造出个性化的桌面环境。 这款软件拥有众多令人惊叹的功能。其中最值得一提的是&#xff0c;它…

视频监控/安防监控/AI视频分析/边缘计算EasyCVR平台如何调取登录接口获取token?

安防视频监控管理平台/视频汇聚/视频云存储平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、云存储、AI智能分析等&#xff0c;视频监控智能分析平台EasyCVR融合性强、…

Vue3修改数组问题

Vue3修改数组问题 1. reactive2. ref总结 vue3中使用组合式式API时定义响应式数据需要使用reactive或者ref,两者使用时有些许不同,下面通过重新赋值数组来说明两者的不同 1. reactive 主要用来定义复杂一些的响应式数据 先清空再赋值 const datas reactive([{id:1,name: 孙…

DataGrip 2023 年下载、安装教程、亲测可用

文章目录 前言1. 下载2. 安装3、DataGrip 常用操作4 推荐阅读 前言 DataGrip 是 JetBrains 发布的多引擎数据库环境&#xff0c;支持 MySQL 和 PostgreSQL&#xff0c;Microsoft SQL Server 和 Oracle&#xff0c;Sybase&#xff0c;DB2&#xff0c;SQLite&#xff0c;还有 Hy…

使用dockerfile文件部署Python+PyWebIO项目

1、安装docker 教程详见之前的内容。https://blog.csdn.net/weixin_44691253/category_12101661.html 2、打包好Python项目 之前的文章中有提到我编写测试工具使用的框架&#xff1a;PythonRequestsPyWebIO框架详解&#xff0c;编写测试工具提高团队测试效率 打包项目时&am…

org.apache.flink.table.api.TableException: Sink does not exists

FlinkSQL_1.12_用DDL实现Kafka到MySQL的数据传输_实现按照条件进行过滤写入MySQL_flink从kafka拉取数据并过滤数据写入mysql_旧城里的阳光的博客-CSDN博客 参考这篇文章&#xff0c;写了kafka到mysql的代码例子&#xff0c;因为自己改了表结构&#xff0c;运行下面代码&#x…

Ceph入门到精通-Macvlan网络模式

Docker中的Macvlan网络模式提供了一种将容器直接连接到宿主机网络的方式&#xff0c;使得容器可以拥有自己的MAC地址和与宿主机网络的直接连接。以下是使用Macvlan网络模式的一般步骤&#xff1a; 创建Macvlan网络&#xff1a; docker network create -d macvlan --subnet<s…

Java中的队列Queue

Queue(队列)是一种在计算机科学中常见的数据结构,它基于先进先出(FIFO)的原则,即最先进入队列的元素最先出队。在Java中,Queue是一个接口,定义了一组操作队列的方法,而具体的实现类可以选择性地实现这些方法。 以下是Queue的一些常见用途和操作: 添加元素: 使用off…

【openscreen】FrameList的插入

新版本也有此代码 E:\chromium\src\media\cast\test\receiver\frame_buffer.cc Framer 类的代码都没加锁。 FrameList :frame_id 和 FrameBuffer 的对应关系 typedef std::map<uint32, linked_ptr<FrameBuffer> > FrameList;Framer 管理 FrameList bool Framer::

淘宝双11数据分析与预测课程案例中(林子雨)错误点总结

问题一&#xff1a;可视化代码中男女买家各个年龄段对比散点图中数值不显示以及坐标不正确问题如下图 解决方法&#xff1a; 1修改坐标 2修改数值 修改后散点图 问题二&#xff1a;各省份的总成交量对比中地图显示不出来&#xff0c;因为该部分代码源码中没有需要自己编写…

Python3.11教程6:标准库简介1——os、shutil、sys、random、time、datetime、 threading

文章目录 一、 文件和目录处理模块1.1 os模块1.2 shutil 模块1.3 文件通配符glob1.4 stat 二、 sys模块2.1 命令行参数列表2.2 -c和-m选项2.3 argparse2.3.1 argparse使用逻辑2.3.2 add_argument()语法 三、 数学3.1 math3.2 random3.3 numpy生成随机数 四、 日期和时间4.1 tim…

排序算法-----插入排序

目录 前言&#xff1a; 插入排序 原理图 代码实现 分析总结 二分法插入排序 代码实现 前言&#xff1a; 嗨嗨^_^&#xff0c;米娜桑&#xff0c;今天我们继续学习排序算法中的插入排序&#xff0c;激不激动&#xff0c;兴不兴奋呢&#xff01;好了废话不多说&#xff0c;…

RFID服装管理系统改善零售供应链

随着时尚零售业的竞争日益激烈&#xff0c;RFID技术正快速地改变着服装管理的方式。我们将探讨RFID服装管理系统的核心优点&#xff0c;以及如何在零售供应链中充分利用它。 首先&#xff0c;让我们了解一下RFID技术是什么。RFID是一种无线通信技术&#xff0c;通过使用RFID标…

国家网络安全周 | 金融日,一起 get金融行业数据安全

2023国家网络安全宣传周 热度一直在持续&#xff01; 9月15日是国家网络安全宣传金融日。 目前随着国际形势愈发严峻&#xff0c;金融机构基础设施的全面数字化升级&#xff0c;带来了全新的安全问题。数据安全不单是技术问题&#xff0c;更是已经成为一个关系社会稳定发展的…

【算法专题突破】滑动窗口 - 水果成篮(13)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;904. 水果成篮 - 力扣&#xff08;Leetcode&#xff09; 题目有很长一段话&#xff0c;但是我们读一遍题目可以提炼转化出题目的要求 &#xff1a; 其实就是找出一个最长…

怎么样把下载到的补丁集成到Win10 ISO镜像中?

怎么样把下载到的补丁集成到Win10 ISO镜像中&#xff1f; 我们需要使用Dism 命令来进行&#xff0c;Win10中已经内置dism 命令如下&#xff1a; 1、首先挂载镜像命令&#xff0c;其中盘符自己更改 dism /mount-wim /wimfile:"i:\install.wim" /index:1 /mountdir:&q…

数字IC验证23915--寄存器方法

文章目录 镜像值与期望值predication的分类自动预测显示预测 uvm_reg的访问方法寄存器健康检查![在这里插入图片描述](https://img-blog.csdnimg.cn/8b1832ab43854068970bb5a66d851d06.png) 镜像值与期望值 寄存器模型中的每一个寄存器&#xff0c;都应该有两个值&#xff0c;…

我的C#基础

using System; namespace HelloWorldApplication }TOC 欢迎使用Markdown编辑器 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。 为帮助您在CSDN创作的文章获得更多曝光和关注&#xff0c;我们为您提供了专属福利&#xff1a; 已注册且未在CSDN平台发布过…

ESIM实战文本匹配

引言 今天我们来实现ESIM文本匹配&#xff0c;这是一个典型的交互型文本匹配方式&#xff0c;也是近期第一个测试集准确率超过80%的模型。 我们来看下是如何实现的。 模型架构 我们主要实现左边的ESIM网络。 从下往上看&#xff0c;分别是 输入编码层(Input Ecoding) 对前…