【C++STL详解 —— vector的介绍及使用】

【C++STL详解 —— vector的介绍及使用】

  • vector的介绍
  • vector的使用
    • vector的构造
    • vector iterator 的使用
      • begin和end
      • rbegin和rend
    • vector 空间增长问题
      • size和capacity
      • reserve和resize
      • empty
    • vector 增删查改
      • push_back和pop_back
      • insert和erase
      • find
      • swap
      • 元素访问
    • vector 迭代器失效问题(重点)
      • 迭代器失效问题举例
      • 迭代器失效解决方法

vector的介绍

 在C++中,vector是一个非常重要和常用的容器类型,它是标准模板库(Standard Template Library, STL)的一部分。简单来说,vector是一个能够存储任意类型元素的动态数组,其大小可以在运行时自动扩展或缩减。

vector的具体特性如下:

  1. 动态数组: 与普通数组不同,vector可以根据需要动态地增加或减少元素,而不需要程序员手动管理内存。
  2. 模板: vector是一个模板类,意味着它可以用来存储任意类型的对象。例如,vector用于存储整数,vector用于存储字符串。
  3. 自动管理内存: vector自动管理其存储的元素的内存。当vector的容量不足以容纳更多元素时,它会自动重新分配内存空间以容纳新元素。
  4. 随机访问: vector支持通过索引快速访问其元素(类似于数组),这意味着你可以直接通过下标来获取或修改任何位置的元素。

vector的使用

vector的构造

  1. 默认构造函数:创建一个空的vector容器。
   std::vector<int> v;
  1. 填充构造函数:创建一个具有特定大小的vector,可以指定元素的初始值。
std::vector<int> v(5, 10); // 创建一个包含5个元素的vector,每个元素的初始值都是10。
  1. 范围构造函数:通过复制另一个容器或数组的元素范围来创建vector。
std::vector<ElementType> v(begin_iterator, end_iterator);


//例子:
std::vector<int> original = {1, 2, 3, 4, 5};
// 假设我们想从original中复制从第二个元素到第四个元素(2, 3, 4)

std::vector<int> subVector(original.begin() + 1, original.begin() + 4);
// subVector现在包含{2, 3, 4}

  1. 拷贝构造函数: 通过复制另一个vector来创建一个新的vector。
std::vector<int> original(5, 10); // original是一个包含5个元素,每个元素值为10的vector。
std::vector<int> v(original); // 通过拷贝original创建一个新的vector v。

  1. 初始化列表构造函数(C++11及之后版本):允许使用初始化列表来创建vector。
std::vector<int> v = {1, 2, 3, 4, 5}; // 使用初始化列表创建vector。

vector iterator 的使用

在这里插入图片描述

iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;

//iterator是typedef定义的一个指向T类型对象的指针,
//而const_iterator是一个指向const T类型对象的指针。

begin和end

begin(): 获取第一个数据位置的iterator/const_iterator
end(): 获取最后一个数据的下一个位置的iterator/const_iterator。

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v(10, 2);
	//正向迭代器遍历容器
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

rbegin和rend

rbegin(): 获取最后一个数据位置的reverse_iterator.
rend(): 获取第一个数据前一个位置的reverse_iterator

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v(10, 2);
	//反向迭代器遍历容器
	vector<int>::reverse_iterator rit = v.rbegin();
	while (rit != v.rend())
	{
		cout << *rit << " ";
		rit++;
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

vector 空间增长问题

size和capacity

size_t size() const;
size_t capacity() const;

容量空间接口说明
size获取数据个数
capacity获取容量大小
  • capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5 倍增长的,g++是按 2 倍增长的。 vs是PJ版本STL,g++是SGI版本STL。
  • reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
  • resize在开空间的同时还会进行初始化,影响size。
	vector<int> v(10, 2);
	cout << v.size() << endl; //获取当前容器中的有效元素个数
	cout << v.capacity() << endl; //获取当前容器的最大容量

在这里插入图片描述

reserve和resize

void reserve(size_type new_cap);
void resize(size_type count, const value_type& value = value_type());

/*
在resize()中,const value_type& value = value_type() 是一个默认参数。
这个参数表示如果调用 resize() 函数时不提供第二个参数(即 value),
则默认使用 value_type() 构造一个新的元素来填充 std::vector 中的新增位置。

在这里,value_type 是 std::vector 存储的元素类型。
例如,如果 std::vector 存储的是 int 类型的元素,
那么 value_type 就是 int。默认构造一个 int 类型的对象会得到值为 0 的对象。
*/
容量空间接口说明
resize改变vector的size
reserve改变vector的capacity

reserve规则:
 1、当所给值大于容器当前的capacity时,将capacity扩大到该值。
 2、当所给值小于容器当前的capacity时,什么也不做。

resize规则:
 1、当所给值大于容器当前的size时,将size扩大到该值,扩大的元素为第二个所给值,若未给出,则默认为0。
 2、当所给值小于容器当前的size时,将size缩小到该值。

vector<int> v(10, 2);
	cout << v.size() << endl; //10
	cout << v.capacity() << endl; //10
	v.reserve(20); //改变容器的capacity为20,size不变
	cout << v.size() << endl; //10
	cout << v.capacity() << endl; //20
	v.resize(15); //改变容器的size为15
	cout << v.size() << endl; //15
	cout << v.capacity() << endl; //20

在这里插入图片描述

empty

bool empty() const;

容量空间接口说明
empty判断是否为空
	vector<int> v(10, 2);
	cout << v.empty() << endl;

在这里插入图片描述

vector 增删查改

push_back和pop_back

void push_back(const T& value);
void pop_back();

通过push_back函数对容器进行尾插,pop_back函数对容器进行尾删。

insert和erase

// insert
iterator insert(iterator pos, const T& value); // 插入单个元素
void insert(iterator pos, size_type count, const T& value); // 插入多个相同值的元素

template<class InputIterator>
void insert(iterator pos, InputIterator first, InputIterator last); // 插入范围内的元素


//erase
iterator erase(iterator pos); // 删除单个元素
iterator erase(iterator first, iterator last); // 删除范围内的元素

通过insert函数可以在所给迭代器位置插入一个或多个元素,通过erase函数可以删除所给迭代器位置的元素,或删除所给迭代器区间内的所有元素(左闭右开)。

vector<int> v1;
	vector<int> v2{ 'a','b','c'};

	v1.insert(v1.begin(), 10);
	v1.insert(v1.begin(), v2.begin(), v2.end());

	for (auto e : v1)
	{
		cout << e << ' ';
	}

在这里插入图片描述

find

template <class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val);

firstlast是迭代器,它们分别指向容器中要进行查找的范围的开始和结束。注意,范围包括first指向的元素,但不包括last指向的元素。
val是要查找的值。返回值是一个迭代器,指向在范围[first, last)中找到的第一个与val相等的元素。如果找不到这样的元素,则返回值等于last

std::vector<int> vec = {1, 2, 3, 4, 5, 6};

    auto it = std::find(vec.begin(), vec.end(), 5);

    if (it != vec.end()) {
        std::cout << "Found the number: " << *it << std::endl;
    } else {
        std::cout << "Number not found." << std::endl;
    }

注意: find函数是在算法模块(algorithm)当中实现的,不是vector的成员函数。

swap

通过swap函数可以交换两个容器的数据空间,实现两个容器的交换。

	vector<int> v1(10, 1);
	vector<int> v2(10, 2);

	v1.swap(v2); //交换v1,v2的数据空间

元素访问

vector当中实现了 [ ] 操作符的重载,因此我们也可以通过“下标+[ ]”的方式对容器当中的元素进行访问。

vector<int> v(10, 1);
	//使用“下标+[]”的方式遍历容器
	for (size_t i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;

vector 迭代器失效问题(重点)

迭代器失效问题举例

  1. 插入(push_back, insert):当向vector插入元素时,如果需要更多的内存空间以容纳新元素,vector可能会重新分配其内存以获得更大的容量。这种重新分配会使所有之前的迭代器、引用和指针失效。
  2. 删除(erase, pop_back):从vector中删除元素后,所有指向被删除元素之后元素的迭代器、引用和指针都将失效。
  3. 缩减容量(shrink_to_fit, resize):缩减vector的容量可能导致重新分配内存,从而使现有的迭代器、引用和指针失效。

插入元素导致的迭代器失效
问题:在vector中插入元素导致容器重新分配内存。

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    auto it = vec.begin() + 2; // 指向3
    vec.push_back(6); // 可能导致迭代器it失效,因为可能会重新分配内存

    // 使用失效的迭代器it访问元素
    // std::cout << *it << std::endl; // 未定义行为

    return 0;
}

删除元素导致的迭代器失效
问题:从vector中删除元素导致之后的迭代器失效。

	std::vector<int> vec = {1, 2, 3, 4, 5};
    auto it = vec.begin() + 3; // 指向4
    vec.erase(vec.begin() + 2); // 删除元素3,导致迭代器it失效

    // 使用失效的迭代器it访问元素
    // std::cout << *it << std::endl; // 未定义行为

缩减容量导致的迭代器失效
问题:使用shrink_to_fit或resize缩减vector容量导致的迭代器失效。

	std::vector<int> vec = {1, 2, 3, 4, 5};
    vec.reserve(100); // 预分配较大的内存空间
    auto it = vec.begin() + 2; // 指向3
    vec.shrink_to_fit(); // 缩减容量,可能导致迭代器it失效

    // 使用失效的迭代器it访问元素
    // std::cout << *it << std::endl; // 未定义行为

迭代器失效解决方法

插入元素导致的迭代器失效 -> 解决方法:重新获取迭代器。

// 在push_back后重新获取迭代器
it = vec.begin() + 2;
std::cout << *it << std::endl; // 正确访问

删除元素导致的迭代器失效 -> 解决方法:使用erase返回的迭代器。

// 使用erase返回的迭代器更新it
it = vec.erase(vec.begin() + 2); // 现在it指向4
std::cout << *it << std::endl; // 正确访问

缩减容量导致的迭代器失效 -> 解决方法:避免在需要保持迭代器有效时使用shrink_to_fit,或者在操作后重新获取迭代器。

// 在shrink_to_fit后重新获取迭代器
it = vec.begin() + 2;
std::cout << *it << std::endl; // 正确访问

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue 如何快速上手

目录 1. Vue 是什么 &#xff08;概念&#xff09; 1.1. Vue 的两种使用方式 1.2. 优点 1.3. 缺点 2. 创建 Vue 实例&#xff0c;初始化渲染 2.1. 步骤&#xff08;核心步骤 4步&#xff09; 2.2. 练习——创建一个Vue实例 3. 插值表达式 {{ }} 3.1. 介绍 3.2. 作用…

哈哈哈哈哈

欢迎使用Markdown编辑器 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#xff0c;了解一下Markdown的基本语法知识。 222 我们对Markdown编辑器进行了一些功能拓展与语法支持&#xff0c;…

大创项目推荐 深度学习 python opencv 火焰检测识别

文章目录 0 前言1 基于YOLO的火焰检测与识别2 课题背景3 卷积神经网络3.1 卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV54.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 数据集准备5.1 数…

文件管理--fscanf,fread,fwrite和fprintf

fprintf函数&#xff1a;对于fprintf函数&#xff0c;它和printf一样&#xff0c;但是它的表达式为&#xff1a;int fprintf ( FILE * stream, const char * format, ... );和printf的很相似&#xff0c;但有不一样。它是格式化输出函数&#xff0c;代码为&#xff1a; #includ…

模拟退火遗传算法GASA-附MATLAB代码

模拟退火遗传算法&#xff08;Simulated Annealing Genetic Algorithm&#xff0c;SAGA&#xff09;结合了模拟退火算法&#xff08;Simulated Annealing&#xff0c;SA&#xff09;和遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;的优点&#xff0c;用于解…

数字化导师坚鹏:招商银行数字化转型的4次模式升级与5大关键举措

招商银行数字化转型的4次模式升级与5大关键举措 招商银行数字化转型取得了较大的成功&#xff0c;从目前的财务数据来看&#xff0c;招商银行在数字化转型领域已经成为国内最优秀的股份制银行。招商银行是如何取得数字化转型成功的&#xff1f;从招商银行数字化转型的4次模式升…

先进电气技术 —— 控制理论之控制与扰动的战争

一、与扰动的斗争催生控制理论 在控制理论中&#xff0c;可以说“Identification&#xff08;辨识&#xff09;”、“Observe&#xff08;观测&#xff09;”、“Estimate&#xff08;估计&#xff09;”和“Control&#xff08;控制&#xff09;”这四个核心概念都是为了“消…

Centos7安装Docker与Docker-compose【图文教程】

个人记录 查看一下系统是否已经安装了Docker yum list installed | grep docker如下图代表没有安装Docker 卸载已有Docker yum remove docker docker-common docker-selinux docker-engine切换目录 cd /etc/yum.repos.d/查看当前目录所有的镜像源 ll安装yum-util与devi…

动态规划刷题(算法竞赛、蓝桥杯)--摆花(线性DP)

1、题目链接&#xff1a;[NOIP2012 普及组] 摆花 - 洛谷 #include <bits/stdc.h> using namespace std; const int mod1e67; const int N110; int n,m; int a[N],f[N][N]; //f[n][m]表示前n种花摆m盆的方案数 int main(){scanf("%d %d",&n,&m);for(in…

基于 Docker 的 python grpc quickstart

工作之后一直使用的 RPC 框架是 Apache 的 thrift&#xff0c;现在发现 grpc 更流行&#xff0c;所以也要学习一下&#xff0c;先来简单的跑一下 demo。在本地安装运行也很方便&#xff0c;不过因为有了 docker&#xff0c;所以在 docker 里面安装运行隔离性更好&#xff0c;顺…

并发线程基础第八篇

目录 线程池 自定义线程池 步骤1&#xff1a;自定义拒绝策略接口 步骤2&#xff1a;自定义任务队列 步骤3&#xff1a;自定义线程池 步 骤 4&#xff1a;测 试 ThreadPoolExecutor 线程池状态 构造方法 工作方式 newFixedThreadPool newCachedThreadPool newSingleTh…

算法day30 回溯6

332 重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;所以该行程必须从 JFK …

【网站项目】果蔬经营平台系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

红黑树的性质与操作:吸收红结点及其对树结构的影响

红黑树的性质与操作&#xff1a;吸收红结点及其对树结构的影响 1.红黑树的基本性质2.吸收红结点的过程2.1黑色结点的度2.2 叶结点深度 3.伪代码实现4. C语言代码实现5. 结论 红黑树作为一种高效的自平衡二叉搜索树&#xff0c;在计算机科学中扮演着重要的角色。它通过一系列复杂…

C++理解std::move和转发(std::forward)

理解 std::move 标准库move函数是使用右值引用的模板的一个很好的例子。 幸运的是&#xff0c;我们不必理解move所使用的模板机制也可以直接使用它。 但是&#xff0c;研究move是如何工作的可以帮助我们巩固对模板的理解和使用。 我们注意到&#xff0c;虽然不能直接将一个…

【C语言】linux内核pci_register_driver

一、注释 以下是对源代码中英文注释的中文翻译&#xff0c;可能会略去一些编程上的专有词汇&#xff08;例如函数名、类型名等&#xff09;&#xff0c;以使翻译更易理解。 // drivers\pci\pci-driver.c /*** __pci_register_driver - 注册一个新的PCI驱动* drv: 需要注册的驱…

【QT入门】 无边框窗口设计综合运用之自定义标题栏带圆角阴影的窗口

往期回顾&#xff1a; 【QT入门】 自定义标题栏界面qss美化按钮功能实现-CSDN博客 【QT入门】 无边框窗口设计之实现窗口阴影-CSDN博客 【QT入门】 无边框窗口设计之实现圆角窗口-CSDN博客 【QT入门】 无边框窗口设计综合运用之自定义标题栏带圆角阴影的窗口 一、最终效果 二、…

数据结构进阶篇 之 【交换排序】(冒泡排序,快速排序递归、非递归实现)

当你觉的自己不行时&#xff0c;你就走到斑马线上&#xff0c;这样你就会成为一个行人 一、交换排序 1.冒泡排序 BubbleSort 1.1 基本思想 1.2 实现原理 1.3 代码实现 1.4 冒泡排序的特性总结 2.快速排序 QuickSort 2.1 基本思想 2.2 递归实现 2.2.1 hoare版 2.2.2 …

开发环境->生产环境

1、数据迁移 不涉及docker # 以数据库用户导出数据 mysqldump -h 192.168.1.168 -P 3307 -u abragent -pabragebb17 abragent > abragent.sql# 以root用户导出数据 mysqldump -h 192.168.1.168 -P 3307 -u root -p8d3Ba1b abragent > abragent.sql 涉及docker …

java自动化学习-IntelliJ IDEA新建项目

1、新建项目 2、新建类&#xff0c;右键”src” > “new” >”Java Class” 3、重命名类名