vector的使用(部分接口)

news2024/12/28 18:25:12

1.vector的使用

1.1vector的定义

(constructor)构造函数声明接口说明
vector()无参构造
vector (const vector& x)拷贝构造

1.2vector iterator 的使用

iterator的使用接口说明
begin +end获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置的iterator/const_iterator

1.3 vector 空间增长问题

容量空间接口说明
resize改变vector的size
reserve改变vector的capacity
  • capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。
  •  reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
  • resize在开空间的同时还会进行初始化,影响size。分三种情况:可能是插入数据,也可能是扩容+插入数据,还有可能是删除数据。

1.4vector 增删查改

vector增删查改接口说明
push_back()尾插
pop_back()尾删
operator[]像数组一样访问

1.5 vector 迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装。比如:扩容缩容导致迭代器失效,insert才是真正的迭代器失效,而且还是偶发性的,还有就是没有指向原来的位置了

对于vector可能会导致其迭代器失效的操作有:

  1. 会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back等
    #include <iostream>
    using namespace std;
    #include <vector>
    int main()
    {
    	vector<int> v{ 1,2,3,4,5,6 };
    	auto it = v.begin();
    	// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容
    	// v.resize(100, 8);
    	 
    	// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变
    	// v.reserve(100);
    	 
    	// 插入元素期间,可能会引起扩容,而导致原空间被释放
    	// v.insert(v.begin(), 0);
    	// v.push_back(8);
    	
    	// 给vector重新赋值,可能会引起底层容量改变
    	v.assign(100, 8);
    
        while (it != v.end())
        {
            cout << *it << " ";
            ++it;
        }
        cout << endl;
    }

    出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。
    解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新赋值即可。

  2. 指定位置元素的删除操作--erase

    #include <iostream>
    using namespace std;
    #include <vector>
    int main()
    {
    	int a[] = { 1, 2, 3, 4 };
    	vector<int> v(a, a + sizeof(a) / sizeof(int));
    
    	// 使用find查找3所在位置的iterator
    	vector<int>::iterator pos = find(v.begin(), v.end(), 3);
    
    	// 删除pos位置的数据,导致pos迭代器失效。
    	v.erase(pos);
    	cout << *pos << endl; // 此处会导致非法访问
    	return 0;
    }

    erase 删除pos位置元素后,pos之后的位置的元素就会往前移,没有导致底层空间的改变,理论上迭代器不应该会失效。但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。vs里erase后,迭代器就失效了(有强制检查),因为erase可能会缩容

  3. 结论:insert,erase形参都可能会失效。原则:是insert和erase过的,迭代器不要使用。

2.手搓reserve的补充

先看一下vector<string> 的物理图

void reserve(size_t n)
{
    if (n > capacity)
    {
        size_t old = size();// size是一个求长度的函数
        T* tmp = new T[n];
        if (_start)
        {
            memcpy(tmp, _start, old*sizeof(T));
            delete[] _start;
        }

        _start = tmp;
        _finish = _start + old;
        _endofstorage = _start+n;
    }
}

memory在深拷贝自定义类型就是浅拷贝,delete先析构函数再释放空间,会变成野指针。

解决:

  • 针对string进行深拷贝,没有初始化的空间用定位new进行初始化,调用赋值解决(赋值有深拷贝)
  • 引用计数的浅拷贝,没有人写就赚了,不用新开辟空间
  • 把memcpy和memmove都要改
    void reserve(size_t n)
    {
        if (n > capacity)
        {
            size_t old = size();// size是一个求长度的函数
            T* tmp = new T[n];
            if (_start)
            {
                //memcpy(tmp, _start, old*sizeof(T));
                for (size_t i = 0; i < old; i++)
    			{
    				//没有初始化的空间用定位new进行初始化,调用赋值解决(赋值有深拷贝)
    				tmp[i] = _start[i];
    			}
    
                delete[] _start;
            }
    
            _start = tmp;
            _finish = _start + old;
            _endofstorage = _start+n;
        }
    }

3.支持迭代器区间构造

  1. push_back插入就行
  2. 用来干什么呢? 初始化的时候可以用,比如用v1初始化v2,用你的一段区间初始化我

  3. 为什么还要用模版?只要你能用迭代器都能初始化,类型符合。比如可以用数组、链表初始化你。也就是泛型,first,last没有规定是什么。原生指针是天然迭代器,底层还是指针

  4. 总结:指向连续物理空间的指针就是天然的迭代器

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

4.用n个val初始化

  1. 非法的间接寻址:对不能解引用的类型进行解引用
    void test_vector2()
    {
    	vector<string> v1(5, "1111");
    	for (auto e : v1)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    
    	vector<int> v2(5, 1);
    	for (auto e : v2)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    }

    运行结果:

  2. 有问题的原因是有更匹配的用上面的那个区间。 有现成的吃现成的,没有才去吃自助餐(模版)。如果没有上面这个模板是没有问题的,当前原因就是有更匹配的

  3. 怎么解决?强制吃更匹配的,加个int。 这样库里有size_t 的还有int 的,这样就可以调用了

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

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

相关文章

【数据结构】单链表的特点

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;数据结构 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

UML——类图详解

目录 1. 前言 2. 类图概述 3. 类图表示法 3.1 类的表示方式 3.2 类与类之间关系的表示方式 (1)继承(泛化)关系 (2)实现关系 (3)依赖关系 (4)一般关联关系 (5)聚合关系 (6)组合关系 1. 前言 UML全称(Unified Modeling Language)&#xff0c;译为统一建模语言&#x…

Android自定义ListView单击事件失效的解决方法

因为自带的listView不能满足项目需求&#xff0c;通过实现自己的Adapter去继承ArrayAdapter 来实现自定义ListView的Item项目。 出现点击ListView的每一项都不会执行setOnItemClickListener 里面的onItemClick 方法。 原因是item里面存在一些子控件&#xff0c;默认点击获取的…

使用 PhpMyAdmin 安装 LAMP 服务器

使用 PhpMyAdmin 安装 LAMP 服务器非常简单。按照下面所示的步骤&#xff0c;我们将拥有一个完全可运行的 LAMP 服务器&#xff08;Linux、Apache、MySQL/MariaDB 和 PHP&#xff09;。 什么是 LAMP 服务器&#xff1f; LAMP 代表 Linux、Apache、MySQL 和 PHP。它们共同提供…

如何在PostgreSQL中实现分布式事务,特别是在多节点集群环境中?

文章目录 解决方案&#xff1a;使用Citus实现分布式事务步骤一&#xff1a;安装和配置Citus步骤二&#xff1a;定义分布式表和分布键步骤三&#xff1a;执行分布式事务示例代码 总结 在PostgreSQL中实现分布式事务&#xff0c;特别是在多节点集群环境中&#xff0c;是一个复杂但…

c++ - 模板(一)

文章目录 一、函数模板 一、函数模板 1、概念 函数模板代表了一个函数家族&#xff0c;该函数模板与类型无关&#xff0c;在使用时被参数化&#xff0c;根据实参类型产生函数的特定 类型版本。 2、原理 函数模板是一个蓝图&#xff0c;它本身并不是函数&#xff0c;是编译器用…

【学习】如何高效地进行集成测试

在软件开发的过程中&#xff0c;测试环节至关重要。而在这其中&#xff0c;集成测试更是保证软件质量的关键步骤之一。本文将探讨如何高效地进行集成测试&#xff0c;以确保软件的稳定性和可靠性。 一、什么是集成测试 集成测试是指在单元测试的基础上&#xff0c;将模块按照设…

opencv可视化图片-----c++

可视化图片 #include <opencv2/opencv.hpp> #include <opencv2/core.hpp> #include <filesystem>// 将数据类型转换为字符串 std::string opencvTool::type2str(int type) {std::string r;uchar depth type & CV_MAT_DEPTH_MASK;uchar chans 1 (typ…

Redis入门到通关之Redis网络模型-用户空间和内核态空间

文章目录 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 请回答1024的博客 关于博主&#xff1a; 我是 请回答1024&#xff0c;一个追求数学与计算的边界、时间与空间的平衡&#xff0c;0与1的延伸的后端开发者。 博客特色&#xff1a; 在我的…

【行为型模式】解释器模式

一、解释器模式概述 解释器模式定义&#xff1a;给分析对象定义一个语言&#xff0c;并定义该语言的文法表示&#xff0c;再设计一个解析器来解释语言中的句子。也就是说&#xff0c;用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口&#xff0c;该接口…

STM32中的PWM

一、介绍 二、制作一个呼吸灯的效果&#xff08;使用PWM&#xff09; 原理是中心对齐的方式 学会分析复用管脚&#xff08;根据手册&#xff09; 配置 更正:是 最后一个输出的模式 最后生成代码 三、代码 要修改的业务代码 改代码&#xff0c;实现呼吸灯

科技赋能无人零售

科技赋能无人零售&#xff0c;使其具备以下独特优势&#xff1a; 1. 全天候无缝服务 &#xff1a;无人零售店依托科技&#xff0c;实现24小时不间断运营&#xff0c;不受人力限制&#xff0c;满足消费者随时购物需求&#xff0c;尤其惠及夜间工作者、夜猫子及急需购物者&…

聊聊.NET Core处理全局异常有那些方法

简述 处理全局异常的方法有IExceptionFilter&#xff08;异常处理&#xff09;&#xff0c;使用中间件异常处理&#xff0c;使用框架自带异常中间件等。考点 考察对异常处理方式的熟悉程度和广度&#xff0c;以及对中间件、过滤器熟练程度。 下面分别具体介绍三种处理异常的…

k-均值聚类

K均值聚类&#xff08;K-means clustering&#xff09;是一种常用的无监督学习方法&#xff0c;用于将一组数据点划分为K个簇&#xff08;cluster&#xff09;。 它的目标是将相似的数据点归到同一个簇中&#xff0c;同时使得不同簇之间的数据点尽可能不相似。K均值聚类算法的…

Golang | Leetcode Golang题解之第47题全排列II

题目&#xff1a; 题解&#xff1a; func permuteUnique(nums []int) (ans [][]int) {sort.Ints(nums)n : len(nums)perm : []int{}vis : make([]bool, n)var backtrack func(int)backtrack func(idx int) {if idx n {ans append(ans, append([]int(nil), perm...))return}…

有效三角形的个数 ---- 双指针

题目链接 题目: 分析: 这道题的意思就是将数组的元素, 拿出三个数, 能构成三角形就是有效的判断是否能构成三角形的条件: 两边之和大于第三边, 我们只需找到三个数中最小的两个数之和是否大于第三边, 大于则可以构成三角形解法一: 暴力解法, 即找到所有的三元组, 并挨个判断,…

「 网络安全常用术语解读 」SBOM主流格式SPDX详解

SPDX&#xff08;System Package Data Exchange&#xff09;格式是一种用于描述软件组件&#xff08;如源代码&#xff09;的规范&#xff0c;它提供了一种标准化的方法来描述软件组件的元数据&#xff0c;包括其许可证、依赖项和其他属性。SPDX最初由Linux基金会于2010年发起&…

vue 实现左侧导航栏,右侧锚点定位滚动到指定位置(超简单方法)

项目截图&#xff1a; 实现方法&#xff1a; 点击左侧菜单根据元素id定位到可视内容区域。 浏览器原生提供了一种方法scrollIntoView 。 通过scrollIntoView方法可以把元素滚动到可视区域内。 behavior: "smooth"是指定滚动方式为平滑效果。 具体代码如下&#xf…

linux安装MySQL8.0,密码修改权限配置等常规操作详解

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【一刷剑指Offer】面试题 8:旋转数组的最小数字

力扣对应题目链接&#xff1a;154. 寻找旋转排序数组中的最小值 II - 力扣&#xff08;LeetCode&#xff09; 牛客对应题目链接&#xff1a; 旋转数组的最小数字_牛客题霸_牛客网 (nowcoder.com) 核心考点 &#xff1a;数组理解&#xff0c;二分查找&#xff0c;临界条件。 一…