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

news2024/10/10 0:29:55

【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; // 正确访问

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

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

相关文章

案例:非功能性需求的设计

在咨询中看到很多项目组对于非功能性需求没有做设计&#xff0c;很多项目组在设计文档中仅仅是把非功能性需求的描述拷贝到设计文档的非功能性章节。因此特地设计了两个简单的需求给大家参考&#xff0c;希望能够引导设计人员重视非功能性需求的设计。

软件设计师-案例分析2

文章目录 除09-1520上-结构化分析20上-数据库分析20上-面向对象分析与设计 除09-15 20上-结构化分析 问题1&#xff1a; 问题2&#xff1a; 问题3&#xff1a; 问题4&#xff1a; 回答1&#xff1a;E1检测设备&#xff1b; E2管理员&#xff1b;E3检测业务员&#xff1b;…

Java多态世界(day18)

多态&#xff1a;重写的方法调用和执行 1.静态绑定&#xff1a;编译器在父类中找方法&#xff0c;如&#xff1a; 上面的eat&#xff08;&#xff09;方法是先在父类中找方法&#xff0c;父类没有的话&#xff0c;就算子类有编译也会报错。&#xff08;如果引用方法在父类中存…

HashMap为啥线程不安全?

1. HashMap1.7在多线程并发下扩容时&#xff0c;头插法会出现环。 /*** Rehashes the contents of this map into a new array with a* larger capacity. This method is called automatically when the* number of keys in this map reaches its threshold.** If current cap…

使用Detours进行HOOK

文章目录 Detours介绍Detours配置Detours进行Sleep Hook Detours介绍 Detours是微软研究院开发的一款软件工具&#xff0c;用于Windows平台上的应用程序重定向和修改。 它可以在运行时修改应用程序的执行路径&#xff0c;允许开发人员注入自定义代码来改变应用程序的 行为&…

STM32 定时器外部时钟与循迹模块

1、上篇文章介绍了定时器使用内部时钟信号计数&#xff0c;实现计数、更新中断等功能。 2、可不可以利用定时器对来自外部的信号进行计数&#xff1f;也就是对输入io的信号计数&#xff1f; 3、可以 1、定时器外部时钟 STM32的通用定时器和高级定时器都将外部信号引入…

深入解析:链游、DApp、公链、NFT与交易所开发的全景图

随着数字货币和区块链技术的迅速发展&#xff0c;链游开发、DApp开发、公链开发、NFT开发以及交易所开发等领域吸引了越来越多的关注。本文将以3000字的篇幅&#xff0c;对这些领域进行详细解析&#xff0c;探讨它们的意义、应用场景以及未来发展趋势。 链游开发&#xff08;Bl…

每日面经分享(python进阶 part2)

Python中的装饰器和上下文管理器区别是什么&#xff1f;它们分别适用于哪些场景&#xff1f; a. 装饰器用于在函数或类的外部添加额外功能&#xff0c;而上下文管理器用于管理资源的获取和释放。 b. 装饰器是一种用于修改函数或类行为的技术。适用于需要在函数或类的外部添加额…

Electron 打包自定义NSIS脚本为安装向导增加自定义页面增加输入框

Electron 打包工具有很多&#xff0c;如Electron-build、 Electron Forge 等&#xff0c;这里使用Electron-build&#xff0c;而Electron-build使用了nsis组件来创建安装向导&#xff0c;默认情况nsis安装向导不能自定义安装向导界面&#xff0c;但是nsis提供了nsis脚本可以扩展…

YOLO火灾烟雾检测数据集:20000多张,yolo标注完整

YOLO火灾烟雾检测数据集&#xff1a;一共20859张图像&#xff0c;yolo标注完整&#xff0c;部分图像应用增强 适用于CV项目&#xff0c;毕设&#xff0c;科研&#xff0c;实验等 需要此数据集或其他任何数据集请私信

kubadm部署kubernetes

什么是kubernetes Kubernetes是一款应用于集群的&#xff0c;容器自动部署、扩展和管理的开源平台&#xff0c;提供了一种以容器为中心的基础架构。利用kubernetes&#xff0c;你可以快速高效地响应客户如下请求&#xff1a; 应用程序的动态、精准部署应用程序的动态扩展无缝推…

vscode + wsl1 搭建远程C/C++开发环境

记录第一次搭建环境过程。 搭建C/C开发环境有很多种方式&#xff0c;如 MinGW vscode&#xff08;MinGW 是GCC的Windows版本&#xff0c;本地编译环境&#xff09;SSH隧道连接 vscode&#xff08;远程Linux主机&#xff09;wsl vscode&#xff08;远程Linux环境&#xff09…

第14章 数据结构与集合源码

一 数据结构剖析 我们举一个形象的例子来理解数据结构的作用&#xff1a; 战场&#xff1a;程序运行所需的软件、硬件环境 战术和策略&#xff1a;数据结构 敌人&#xff1a;项目或模块的功能需求 指挥官&#xff1a;编写程序的程序员 士兵和装备&#xff1a;一行一行的代码 …

GPT4不限制使用次数了!GPT5即将推出了!

今天登录到ChatGPT Plus账户&#xff0c;出现了如下提示&#xff1a; 已经没有了数量和时间限制的提示。 更改前&#xff1a;每 3 小时限制 40 次&#xff08;团队计划为 100 次&#xff09;&#xff1b;更改后&#xff1a;可能会应用使用限制。 GPT-4放开限制 身边订阅了Ch…

C语言——字符串函数

一.前言 我们在日常写代码的过程中&#xff0c;经常会对字符串进行处理的过程。而在C语言中的<string.h>中&#xff0c;包含了众多字符串函数&#xff0c;我们可以借助这些字符串函数来对其进行各种操作。 二.strlen函数 strlen函数的作用是求出所传字符串的长度。该函…

图片改大小尺寸怎么改?几个修改图片尺寸的方法

日常生活和工作中&#xff0c;图片的大小和尺寸对于我们的工作和生活都至关重要&#xff0c;因此我们经常需要调整图片的大小。我们都知道压缩图是一款功能强大的图片在线处理工具&#xff0c;那么用它怎么调整图片大小呢&#xff1f;下面就让我们一起来看一下具体的操作步骤。…

网络与并发编程(二)

线程_信号量 互斥锁使用后&#xff0c;一个资源同时只有一个线程访问。如果某个资源&#xff0c;我们同时想让N个(指定数值)线程访问&#xff1f;这时候&#xff0c;可以使用信号量。 信号量控制同时访问资源的数量。信号量和锁相似&#xff0c;锁同一时间只允许一个对象(进程…

Python项目21:一个简单的记账系统(收入+支出+查询)

------------★Python练手项目源码★------------ Python项目源码20&#xff1a;银行管理系统&#xff08;开户、查询、取款、存款、转账、锁定、解锁、退出&#xff09; Python项目19&#xff1a;学员信息管理系统&#xff08;简易版&#xff09; Python项目18&#xff1a;…

IDEA配置本地Maven(解决依赖下载缓慢)

1.下载Maven Maven下载页 根据需要选择下载其中一个&#xff0c;我选了zip格式的 将下载好的apache-maven-3.9.5解压到你想要的目录下 2.配置系统环境 设置系统环境变量 MAVEN_HOME 为安装路径的bin目录 变量名&#xff1a;MAVEN_HOME 变量值&#xff1a;写你的 apache-m…

远程登录服务器(ubuntu20.04)在自己账号下的虚拟环境(python3.6)安装Jupyter并连接pycharm使用

参考&#xff1a;Jupyter notebook/lab安装及远程访问 1、安装jupyter pip install notebook遇到的问题&#xff1a; &#xff08;1&#xff09;运行这个指令之前尝试了好多方法都安不上 此前还尝试了更新pip之类的&#xff0c;大家安不上也可以先更新pip试试。 &#xff0…