C++:vector容器

news2025/1/10 12:12:18

概览

`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++程序的开发效率和代码质量。

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

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

相关文章

酒店智能插座在酒店智慧化中的重要性

在当今数字化和智能化的时代&#xff0c;酒店行业也在不断追求创新和提升服务品质&#xff0c;以满足客人日益增长的需求。酒店智能插座作为酒店智慧化的重要组成部分&#xff0c;发挥着不可忽视的作用。 提升客人的便利性&#xff1a; 酒店智能插座能够为客人提供更加便捷的充…

使用 Java Swing 的 IMEI 验证器

一.介绍 本文档介绍如何使用 Java Swing 创建一个简单的 IMEI 验证器应用程序。 二.什么是 IMEI 号码 IMEI 代表国际移动设备识别码。IMEI 用于在移动设备连接到网络时对其进行识别。每个 GSM、CDMA 或卫星移动设备都有唯一的 IMEI 号码。此号码将印在设备电池组件内。用户可…

Flutter GPU 是什么?为什么它对 Flutter 有跨时代的意义?

Flutter 3.24 版本引入了 Flutter GPU 概念的新底层图形 API flutter_gpu &#xff0c;还有 flutter_scene 的 3D 渲染支持库&#xff0c;它们目前都是预览阶段&#xff0c;只能在 main channel 上体验&#xff0c;并且依赖 Impeller 的实现。 Flutter GPU 是 Flutter 内置的底…

Python3 第六十六课 -- CGI编程

目录 一. 什么是 CGI 二. 网页浏览 三. CGI 架构图 四. Web服务器支持及配置 五. 第一个CGI程序 5.1. HTTP 头部 5.2. CGI 环境变量 六. GET和POST方法 6.1. 使用GET方法传输数据 6.1.1. 简单的url实例&#xff1a;GET方法 6.1.2. 简单的表单实例&#xff1a;GET方法…

暑期数据结构 空间复杂度

3&#xff0e;空间复杂度 空间复杂度也是一个数学表达式&#xff0c;是对一个算法在运行过程中临时占用存储空间大小的量度。 空间复杂度不是程序占用了多少bytes的空间&#xff0c;因为这个也没太大意义&#xff0c;所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟…

SAM2:在图像和视频中分割任何内容

SAM 2: Segment Anything in Images and Videos 一、关键信息 1. SAM 2概述&#xff1a; SAM 2 是一种基础模型&#xff0c;设计用于在图像和视频中实现可提示的视觉分割。该模型采用变压器架构和流式内存进行实时视频处理。它在原始的Segment Anything Model&#xff08;SAM…

自用 K8S 资源对象清单 YAML 配置模板手册-1

Linux 常用资源对象清单配置速查手册-1 文章目录 1、Pod 容器集合2、Pod 的存储卷3、Pod 的容器探针4、ResourceQuota 全局资源配额管理5、PriorityClass 优先级类 管理多个资源对象清单文件常用方法&#xff1a; 使用 sed 流式编辑器批量修改脚本键值进行资源清单的创建&am…

【高中数学/函数/值域】求f(x)=(x^2+1)^0.5/(x-1) 的值域

【问题】 求f(x)(x^21)^0.5/(x-1) 的值域 【来源】 《高中数学解题思维策略》P3 例1-1 杨林军著 天津出版传媒集团出版 【解答】 表达式说明f(x)(x^21)^0.5/(x-1)f(x)((x^21)/(x-1)^2)^0.5准备采用配方法f(x)(12/(x-1)2/(x-1)^2)^0.5(1)式f(x)(2*(1/(x-1)1/2)^21/2)^0.5(2)…

Pytorch系列-张量的类型转换

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 张量转换为NumPy数组 使用Tensor.numpy()函数可以将张量转换为ndarray数组 # 1.将张量转换为numpy数组 data_tensortorch.tensor([2,3,4]) # 使用张量对象中的numpy函数进行转…

LiveNVR监控流媒体Onvif/RTSP常见问题-页面上传SSL证书配置开启 HTTPS 服务?什么时候必须要开启HTTPS服务?

LiveNVR常见问题-页面上传SSL证书配置开启 HTTPS 服务&#xff1f;什么时候必须要开启HTTPS服务&#xff1f; 1、配置开启HTTPS1.1、准备https证书1.2、配置HTTPS端口1.3、配置证书路径1.3、 页面上传SSL证书 2、验证HTTPS服务3、为什么要开启HTTPS4、RTSP/HLS/FLV/RTMP拉流Onv…

Vue3+TS+element plus实现一个简单列表页面

期望完成效果 1.创建一个api api内容&#xff1a; 根据接口&#xff1a; 修改 url 和 函数的参数 以及 params里的内容 import { request } from "/utils/service" /** 查 */ export function getDyLogDataApi(page: any, limit: any, campaign_id: any, adgroup_id…

使用Packer构建镜像

什么是Packer Packer 是一个强大的工具&#xff0c;它可以帮助我们轻松地构建各种类型的镜像&#xff0c;如虚拟机镜像、Docker 镜像等。 Packer 的工作原理是通过定义一个配置文件&#xff0c;该文件描述了要构建的镜像的特征和要求。然后 Packer 使用这个配置文件来执行一系…

思迈特软件与海量数据库、红莲花安全浏览器完成兼容互认证

近期&#xff0c;思迈特软件信创认证喜讯传来&#xff0c;思迈特商业智能与数据分析软件[简称&#xff1a;Smartbi Insight] V11在数据库、浏览器产品兼容互认取得新突破&#xff0c;Smartbi Insight V11分别同海量数据库G100管理系统[简称&#xff1a;Vastbase G100] V2.2、红…

Java中的线性搜索

一.介绍 在本文中&#xff0c;我们将讨论或描述 Java 线性搜索。这是最简单的搜索方法。在此方法中&#xff0c;在列表中按顺序搜索要搜索的元素。此方法可应用于已排序或未排序的列表。 二.线性搜索&#xff08;顺序搜索&#xff09; 列表/数组的顺序搜索从列表/数组的开头…

Coco-LIC基于ubuntu的vscode进行断点调试

1、下vscode和插件 参考这个也行 https://zhuanlan.zhihu.com/p/704522656 2、编译debug版本并修改json 要在 Visual Studio Code (VSCode) 中进行断点调试 ROS 任务&#xff0c;你需要进行以下几个步骤&#xff1a; ### 1. 安装所需插件 - **C/C 插件**: 提供对 C 代码的调试…

day13-测试自动化之Selenium的元素定位

一、如何进行元素定位 1.1.元素定位作用 让程序操作指定元素&#xff0c;就必须先找到此元素 1.2.html页面组成格式 1.3.元素定位的概念 元素定位就是通过元素的信息或元素层级结构来定位元素的。 二、浏览器开发者工具 2.1.作用 快速定位元素&#xff0c;查看元素信息 2.2.谷…

《Advanced RAG》-06-探索RAG技术 Query Rewriting

摘要 详细阐述了多种查询重写技术&#xff0c;这些技术用于在检索增强生成&#xff08;RAG&#xff09;中优化查询和文档之间的语义匹配。 首先&#xff0c;介绍了假设文档嵌入&#xff08;HyDE&#xff09;方法&#xff0c;它通过生成假设文档并将其与原始查询结合&#xff0c…

卡码网KamaCoder 104. 建造最大岛屿

题目来源&#xff1a;104. 建造最大岛屿 C题解&#xff1a;先用深度优化算法计算每个孤岛的面积&#xff0c;然后给每个孤岛编号&#xff08;如果孤岛是U型的&#xff0c;防止面积加重复了&#xff09;&#xff0c;再去遍历每个海水区域&#xff0c;计算最大面积。 #include &…

jenkins+gitlab实现微服务的差异化部署

前景&#xff1a; Jenkins 和 GitLab 结合实现微服务的差异化部署具有多方面的意义和优势&#xff0c;主要包括以下几点&#xff1a; 自动化和持续集成&#xff1a;通过 Jenkins 可以实现从代码提交到部署的全自动化流程。这种自动化确保了每次代码变更都能够快速、可靠地构建…

【Python】数据类型之集合

集合是一个无序、可变、不允许元素重复的容器。 1、定义 v1{11,22,33} 1&#xff09;&#xff09;无序&#xff1a;集合无法通过索引取值。 2&#xff09;&#xff09;可变&#xff1a;可以添加和删除集合中的元素。 3&#xff09;&#xff09;集合不允许元素重复。 例如…