当前位置: 首页 > news >正文

C++:vector容器

概览

`std::vector`是C++标准模板库(STL)中的一种动态数组容器。它提供了一种类似于数组的数据结构,但是具有动态大小和更安全的内存管理。

定义和基本特性

      `std::vector`是C++标准库中的一

个序列容器,它代表了能够动态改变大小的数组。与普通数组一样,向量使用连续的存储位置来存放其元素,这使得可以通过指针偏移直接且高效地访问元素,就像操作数组一样。然而,与数组不同的是,向量的大小可以动态变化,其存储管理由容器自动处理。

在内部,向量使用动态分配的数组来存储元素。为了适应增长,这个数组可能需要重新分配空间,这意味着创建一个新的数组并将所有元素移动到新位置。由于重新分配涉及大量的计算资源,向量并不会在每次插入新元素时都重新分配内存。

        相反,向量容器可能会预先分配额外的空间以预留增长空间,因此容器的实际容量可能大于严格包含其元素所需的大小。库可以采用不同的策略来平衡内存使用和重新分配,但无论如何,重新分配应该发生在对数增长间隔的大小上,这样向量尾部插入单个元素的时间复杂度可以达到摊销常数时间(如`push_back`)。

        与数组相比,向量消耗更多的内存,以此换取高效存储管理和动态扩展的能力与其他动态序列容器(如双端队列`deque`、链表`list`和前向链表`forward_list`)相比,向量在访问元素方面效率很高,且在序列尾部添加或移除元素相对高效。但对于在序列非尾部位置插入或移除元素的操作,向量表现不如其他容器,而且其迭代器和引用的稳定性也不及链表和前向链表。

        容器属性总结如下:
- 序列性:容器内的元素按严格的线性顺序排列,可以通过它们的位置直接访问。
- 动态数组:允许通过索引或指针算术直接访问任意元素,并且在序列尾部添加或移除元素速度较快。
- 分配器感知:容器使用分配器对象动态管理其存储需求,这使得可以定制内存分配和释放的策略。

成员类型

 

 常用的成员函数

 

Iterators:

  • begin():返回指向向量开头的迭代器。
  • end():返回指向向量结尾的迭代器。
  • rbegin():返回指向倒序向量开头的反向迭代器。
  • rend():返回指向倒序向量结尾的反向迭代器。
  • cbegin():返回指向向量开头的常量迭代器。
  • cend():返回指向向量结尾的常量迭代器。
  • crbegin():返回指向倒序向量开头的常量反向迭代器。
  • crend():返回指向倒序向量结尾的常量反向迭代器。

Capacity:

  • size():返回向量的大小。
  • max_size():返回最大可能的向量大小。
  • resize():改变向量的大小。
  • capacity():返回已分配的存储空间大小。
  • empty():检查向量是否为空。
  • reserve():请求改变容量。
  • shrink_to_fit():缩小至适合实际大小。

Element access:

  • operator[]:访问元素。
  • at():访问元素(带越界检查)。
  • front():访问首元素。
  • back():访问尾元素。
  • data():访问数据(返回指向元素数组的指针)。

Modifiers:

  • assign():分配向量内容。
  • push_back():在末尾添加元素。
  • pop_back():删除最后的元素。
  • insert():插入元素。
  • erase():删除元素。
  • swap():交换内容。
  • clear():清空内容。
  • emplace():就地构造并插入元素。
  • emplace_back():在末尾就地构造并插入元素。
// 创建一个向量
std::vector<int> vec{1, 2, 3, 4, 5};// 遍历向量
for (auto it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << ' ';
}// 遍历倒序向量
for (auto rit = vec.rbegin(); rit != vec.rend(); ++rit) {std::cout << *rit << ' ';
}// 使用常量迭代器遍历向量
for (auto cit = vec.cbegin(); cit != vec.cend(); ++cit) {std::cout << *cit << ' ';
}// 使用常量反向迭代器遍历倒序向量
for (auto crit = vec.crbegin(); crit != vec.crend(); ++crit) {std::cout << *crit << ' ';
}

 

// 获取向量的大小
std::cout << "Size: " << vec.size() << '\n';// 获取向量的最大可能大小
std::cout << "Max Size: " << vec.max_size() << '\n';// 改变向量的大小
vec.resize(7);// 获取已分配的存储空间大小
std::cout << "Capacity: " << vec.capacity() << '\n';// 判断向量是否为空
if (vec.empty()) {std::cout << "Vector is empty\n";
} else {std::cout << "Vector is not empty\n";
}// 请求改变容量
vec.reserve(10);// 缩小至适合实际大小
vec.shrink_to_fit();

 

// 访问元素
int firstElement = vec.front(); // 获取第一个元素
int lastElement = vec.back();  // 获取最后一个元素
int secondElement = vec[1];   // 使用下标访问第二个元素
int thirdElement = vec.at(2);  // 使用at()函数访问第三个元素,带有越界检查// 直接访问数据
int* dataPtr = vec.data();

 

// 分配向量内容
vec.assign({1, 2, 3});// 添加元素到末尾
vec.push_back(4);// 删除最后一个元素
vec.pop_back();// 插入元素
vec.insert(vec.begin(), 0);// 删除元素
vec.erase(vec.begin());// 交换内容
std::vector<int> anotherVec{6, 7, 8};
vec.swap(anotherVec);// 清空内容
vec.clear();// 就地构造并插入元素
vec.emplace(vec.begin(), 10);// 在末尾就地构造并插入元素
vec.emplace_back(11);

值得注意的点:

erase():

An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.

Member type iterator is a random access iterator type that points to elements.

指向被函数删除的最后一个元素之后的元素的新位置的迭代器。如果操作擦除了序列中的最后一个元素,这就是容器的结尾。

成员类型iterator是一个指向元素的随机访问迭代器类型。

        当`erase`函数被调用来删除容器中的一个或多个元素时,它会返回一个迭代器。这个迭代器指向紧随被删除元素后的新位置处的元素。如果`erase`操作删除的是容器中的最后一个元素,那么返回的迭代器将指向容器的末尾(即`end()`迭代器)。

        这里的`iterator`是容器定义的一种成员类型,它是一种随机访问迭代器,可以用来指向容器中的元素。随机访问迭代器意味着你可以使用诸如`operator+`和`operator-`这样的运算符来在迭代器之间进行移动,也可以使用`operator[]`来进行索引访问。

例如,假设你有一个`std::vector<int>`,并使用`erase`删除了其中的几个元素,那么你可以这样使用返回的迭代器:


std::vector<int> my_vector = {1, 2, 3, 4, 5};
auto it = my_vector.begin() + 2; // 指向3
my_vector.erase(it); // 删除3// it现在指向4,因为3被删除后,4占据了3的位置
// 如果删除的是最后一个元素,it将指向end()

在使用`std::vector`或其他STL容器的`erase`函数时,有几个重要的注意事项,以避免潜在的错误和未定义行为:

1. 迭代器失效:
   当你调用`erase`函数时,所有指向被删除元素及之后元素的迭代器都将失效。这是因为`erase`操作会将之后的元素向前移动以填补空位。因此,你应该立即停止使用任何可能指向这些位置的迭代器,并且在`erase`操作后,任何依赖于这些迭代器的代码都可能产生错误。

2. 返回值的使用:
   `erase`函数返回一个迭代器,指向紧随被删除元素之后的那个元素。如果删除的是容器的最后一个元素,`erase`会返回`end()`迭代器。你应该利用这个返回值来更新你正在使用的迭代器,以防止使用已失效的迭代器。

3. 范围检查:
   确保你正在删除的元素在容器的有效范围内。尝试删除超出容器范围的元素会导致未定义行为,这通常表现为程序崩溃。

4. **性能考量**:
   在`std::vector`中,`erase`操作在容器中间或开头的性能较差,因为它需要移动大量元素。相比之下,在容器末尾使用`pop_back()`删除元素通常更快,因为它不需要移动任何元素。

5. 链式删除:
   如果你打算删除多个元素,特别是连续的元素,最好使用迭代器来跟踪删除操作后的新位置,避免多次无效的迭代器更新。例如,你可以在一个循环中使用`erase`,并立即更新迭代器:

   for (auto it = vec.begin(); it != vec.end(); ) {if (someCondition(*it)) {it = vec.erase(it);} else {++it;}}

6. 并发访问:
   如果你的容器在多线程环境中被多个线程访问,确保在调用`erase`时采取适当的同步措施,以避免数据竞争和未定义行为。

遵循这些指导原则可以帮助你更安全、有效地使用`erase`函数。

insert():

1. 插入单个元素:
   插入单个元素到`std::vector`的指定位置,可以使用以下形式:

   vector_type::iterator insert(position_type position, const T& value);


   这里`position`是一个迭代器,指向新元素应该插入的位置;`value`是要插入的元素的值。

2. 插入范围:
   可以使用两个迭代器来表示一个范围,从而插入一系列元素:

   iterator insert(position_type position, InputIterator first, InputIterator last);


   其中`first`和`last`分别指定了要插入元素的范围。

3. 插入特定数量的相同元素:
   插入多个相同的元素:

   iterator insert(position_type position, size_type count, const T& value);


   这里`count`指定了要插入的元素的数量,`value`则是要插入的元素的值。

注意事项

1. 迭代器失效:
   调用`insert`函数可能会使某些迭代器失效,具体来说,插入点之后的所有迭代器都会失效,因为它们所指向的元素位置发生了变化。你需要在插入操作后重新获取正确的迭代器。

2. 容量调整:
   如果插入元素后容器的大小超过了其当前的容量,`insert`操作可能会触发容器的重新分配(resize),这意味着容器的所有元素会被复制到一个新的内存位置上。这可能会影响性能,特别是在频繁插入元素的情况下。

3. 返回值:
   `insert`函数返回一个迭代器,指向刚刚插入的第一个元素。这在插入单个元素时尤其有用,可以用来获取新元素的位置。

4. 效率考量:
   在`std::vector`中,插入元素的效率取决于插入的位置。在容器的末尾插入元素是最高效的,因为它只需要增加内部计数器而无需移动其他元素。而在容器的开头或中间插入元素则可能需要移动大量元素,因此效率较低。

5. 异常安全性:
   `insert`函数提供强异常安全性保证,即如果在插入过程中发生异常,容器的状态将保持不变,已经完成的插入不会被撤销,也不会有额外的插入。

6. 初始化列表:
   C++11 引入了初始化列表,`std::vector`的`insert`函数也支持使用初始化列表插入一组元素:
 

   template<class InputIt>iterator insert(const_iterator position, initializer_list<T> il);

遵循这些指导原则和注意事项,可以更高效地使用`insert`函数来操作`std::vector`。

了解并正确使用std::vector可以显著提高C++程序的开发效率和代码质量。

相关文章:

C++:vector容器

概览 std::vector是C标准模板库(STL)中的一种动态数组容器。它提供了一种类似于数组的数据结构&#xff0c;但是具有动态大小和更安全的内存管理。 定义和基本特性 std::vector是C标准库中的一 个序列容器&#xff0c;它代表了能够动态改变大小的数组。与普通数组一样&#x…...

深入理解 AWS CodePipeline

AWS CodePipeline 是一种持续交付和持续集成(CI/CD)服务,用于自动化软件发布过程。它通过创建流水线来帮助你自动构建、测试和部署应用程序。以下是对 AWS CodePipeline 的深入理解,包括其工作原理、组件、功能和使用场景: 1. AWS CodePipeline 的基本概念 持续集成和持续…...

Qt:自定义钟表组件

使用QWidget绘制两种钟表组件&#xff0c;效果如下&#xff1a; 源码下载链接&#xff1a;GitHub - DengYong1988/Clock-Widget: Qt 自定义钟表组件 https://download.csdn.net/download/ouyangxiaozi/89616407 主要代码如下&#xff1a; ClockWgt.h #ifndef CLOCKWGT_H #d…...

前端性能优化-web资源加载优先级

前言 资源加载优先级是指在页面渲染的过程中&#xff0c;浏览器决定加载哪些资源并优先加载它们的一种机制。正确配置资源加载的优先级可以显著改善页面加载性能&#xff0c;确保关键资源优先加载&#xff0c;提高用户感知的加载速度。 Web 资源加载方式 同步加载 同步加载…...

Docker-数据卷指令

数据卷挂载修改内容...

Elasticsearch VS Typesense! Elasticsearch未来会被其它搜索引擎取代吗?

近期网上流行一批新的搜索引擎&#xff0c;动不动就大言不惭&#xff0c;要跟龙头老大Elasticsearch比&#xff0c;想把Elasticsearch击败。 1. Typesense 太猖狂了&#xff0c;对Elasticsearch极为不敬 如近期炒作很猖狂的Typesense开源搜索引擎&#xff0c;一出来就急着挑战…...

usb摄像头 按钮 静止按钮

usb摄像头 按钮 静止按钮 来分析一个UVC的摄像头的枚举信息 UVC学习&#xff1a;UVC中断端点介绍 https://www.eet-china.com/mp/a269529.html 输入命令lsusb -d 0c45:62f1 -v https://www.miaokee.com/705548.html >Video Class-Specific VS Video Input Header Descrip…...

SAP MM学习笔记 - 豆知识03 - 安全在库和最小安全在库,扩张物料的保管场所的几种方法,定义生产订单的默认入库保管场所,受注票中设定禁止贩卖某个物料

上一章讲了一些MM模块的豆知识。 - MR21 修改物料原价 - MM02 修改基本数量单位/评价Class - MMAM 修改物料类型/评价Class SAP MM学习笔记 - 豆知识02 - MR21 修改物料原价&#xff0c;MM02 修改基本数量单位/评价Class&#xff0c;MMAM 修改物料类型/评价Class-CSDN博客 …...

激光导航AGV叉车那么多,究竟该怎么选?一篇文章讲明白~

AGV叉车 随着经济的快速发展&#xff0c;大部分企业的物料搬运开始脱离人工劳作&#xff0c;取而代之的是以叉车为主的机械化搬运。AGV叉车是工业搬运车辆&#xff0c;是指对成件托盘货物进行装卸、堆垛和短距离运输作业的各种轮式搬运车辆&#xff0c;主要应用于货场、工厂车间…...

redis面试(七)初识lua加锁脚本

redisson redisson如何来进行redis分布式锁实现的源码&#xff0c;基于redis实现各种各样的分布式锁的原理 https://redisson.org/ 这是官网 https://github.com/redisson/redisson/wiki/Table-of-Content 这是官方文档 开始 demo 建一个普通的工程在pom.xml里引入依赖 <…...

企元数智百年营销史的精粹:借鉴历史创造未来商机

随着时代的发展和科技的进步&#xff0c;传统营销方式正在经历前所未有的颠覆和改变。在这个数字化时代&#xff0c;企业需要不断创新&#xff0c;同时借鉴百年营销史的精粹&#xff0c;汲取历史经验&#xff0c;创造未来商机。而"企元数智"作为现代营销的代表&#…...

Java @SpringBootTest注解用法

SpringBootTest 是 Spring Framework 中的一个注解&#xff0c;用于指示 Spring Boot 应用程序的测试类。当你在测试类上使用 SpringBootTest 注解时&#xff0c;Spring Boot 会启动一个 Spring 应用程序上下文&#xff0c;并且加载应用程序的 application.properties 或 appli…...

构建智能招聘平台:人才招聘系统源码开发指南

本篇文章&#xff0c;小编将详细探讨如何基于人才招聘系统源码开发一个智能招聘平台&#xff0c;为企业的人才战略提供支持。 一、智能招聘平台的核心功能 智能招聘平台的核心在于提高招聘效率和匹配度&#xff0c;这需要集成多个关键功能模块&#xff1a; 1.职位发布与管理…...

Docker + Nacos + Spring Cloud Gateway 实现简单的动态路由配置修改和动态路由发现

1.环境准备 1.1 拉取Nacos Docker镜像 从Docker Hub拉取Nacos镜像&#xff1a; docker pull nacos/nacos-server:v2.4.01.2 生成密钥 你可以使用命令行工具生成一个不少于32位的密钥。以下是使用 OpenSSL 生成 32 字节密钥的示例&#xff1a; openssl rand -base64 321.3 …...

Linux中多线程压缩软件 | Mingz

原文链接&#xff1a;Linux中多线程压缩软件 本期教程 软件网址&#xff1a; https://github.com/hewm2008/MingZ安装&#xff1a; git clone https://github.com/hewm2008/MingZ.git cd MingZ make cd bin ./mingz -h使用源码安装&#xff1a; 若是你的git无法使用安装&am…...

【JavaEE精炼宝库】网络原理基础——UDP详解

文章目录 一、应用层二、传输层2.1 端口号&#xff1a;2.2 UDP 协议&#xff1a;2.2.1 UDP 协议端格式&#xff1a;2.2.2 UDP 存在的问题&#xff1a; 2.3 UDP 特点&#xff1a;2.4 基于 UDP 的应用层协议&#xff1a; 一、应用层 我们 Java 程序员在日常开发中&#xff0c;最…...

【回眸】周中WLB-个人

生活 计划 苏州or杭州or舟山 负负得正 烟火 鲜芋仙 办上海银行的银行卡 申请表材料准备好 个人博客提现签约变现 个人提升 yas补直播笔记&#xff08;听、口&#xff09;1~3课 *2倍 dy学堂 —— 3课时输出博客 个人笔记本搭建环境 副业探索 收集信息差 目前已…...

基于Spring boot + Vue的灾难救援系统

作者的B站地址&#xff1a;程序员云翼的个人空间-程序员云翼个人主页-哔哩哔哩视频 csdn地址&#xff1a;程序员云翼-CSDN博客 1.项目技术栈&#xff1a; 前后端分离的项目 后端&#xff1a;Springboot MybatisPlus 前端&#xff1a;Vue ElementUI 数据库&#xff1a; …...

C#进阶:轻量级ORM框架Dapper详解

C#进阶&#xff1a;轻量级ORM框架Dapper详解 在C#开发中&#xff0c;ORM&#xff08;对象关系映射&#xff09;框架是处理数据库交互的重要工具。Dapper作为一个轻量级的ORM框架&#xff0c;专为.NET平台设计&#xff0c;因其高性能和易用性而备受开发者青睐。本文将详细介绍D…...

【python015】常见成熟AI-图像识别场景算法清单(已更新)

1.欢迎点赞、关注、批评、指正&#xff0c;互三走起来&#xff0c;小手动起来&#xff01; 【python015】常见成熟AI-图像识别场景算法清单及代码【python015】常见成熟AI-图像识别场景算法清单及代码【python015】常见成熟AI-图像识别场景算法清单及代码 文章目录 1.背景介绍2…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”

案例&#xff1a; 某医药分销企业&#xff0c;主要经营各类药品的批发与零售。由于药品的特殊性&#xff0c;效期管理至关重要&#xff0c;但该企业一直面临效期问题的困扰。在未使用WMS系统之前&#xff0c;其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

深度解析:etcd 在 Milvus 向量数据库中的关键作用

目录 &#x1f680; 深度解析&#xff1a;etcd 在 Milvus 向量数据库中的关键作用 &#x1f4a1; 什么是 etcd&#xff1f; &#x1f9e0; Milvus 架构简介 &#x1f4e6; etcd 在 Milvus 中的核心作用 &#x1f527; 实际工作流程示意 ⚠️ 如果 etcd 出现问题会怎样&am…...

用js实现常见排序算法

以下是几种常见排序算法的 JS实现&#xff0c;包括选择排序、冒泡排序、插入排序、快速排序和归并排序&#xff0c;以及每种算法的特点和复杂度分析 1. 选择排序&#xff08;Selection Sort&#xff09; 核心思想&#xff1a;每次从未排序部分选择最小元素&#xff0c;与未排…...

Go爬虫开发学习记录

Go爬虫开发学习记录 基础篇&#xff1a;使用net/http库 Go的标准库net/http提供了完善的HTTP客户端功能&#xff0c;是构建爬虫的基石&#xff1a; package mainimport ("fmt""io""net/http" )func fetchPage(url string) string {// 创建自定…...