[C++进阶篇]STL中vector的使用

news2024/12/22 23:41:25

一、vector的介绍

1.vector的介绍
  • vector是表示可变大小数组的序列容器。
  • vector也采用的连续存储空间来存储元素,就是可以采用下标对vector的元素进行访问,和数组一样。
  • 它的大小是可以动态改变的。

2.重要的接口组成


二、 vector迭代器的使用

2.1 vector iterator 的使用

void testvector2()   
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);


    vector<int>::iterator it = v1.begin();  //普通正向迭代器可以读可以写
	while (it != v1.end())
	{
		*it = *it * 2;
		cout << *it << " ";
		it++;
	}


vector<int>::reverse_iterator vit = v1.rbegin();  //reverse逆置  reserve保留
	while (vit != v1.rend())
	{
		cout << *vit << " ";
		vit++;
	}
	cout << endl;
	for (auto e : v1)     //编译器替换成迭代器生成的
	{
		cout << e << " ";
	}
	cout << endl;
}


void print_vector(const vector<int>& v)  //传引用,加引用就加const,const 对象就要用const的迭代器
{
	vector<int>::const_iterator it = v.begin();
	while (it != v.end())
	{
		//*it = *it + 1;  const的迭代器不可以写,修改
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

 

2.2 vector空间相关函数

在上一章string中我们详细介绍过所以就不去讲解了

但这里我我们要注意一下:

resize:是直接开空间resize(100)是从低一百个位置开始计算

size是100

reserve:是提前开空间,第0个位置

size是0

2.3 vector的增删查改

2.4 find,sort,swap的介绍

参数是一段迭代器区间,在此区间你要添加需要查找的值,找到后返回这个值对应的迭代器位置
若找不到,则返回迭代器last

vector<int> vv{1,2,3,4,5,6,7,8,9};
auto pos = find(vv.begin(),vv.end(),5);
cout<<*pos;

sort函数

他本质就是快排,所以当我们输入一些数的时候,调用迭代器,他会自动排序

vector<int> vv{5,7,3,9,6,4,1,2,8};
sort(vv.begin().vv.end());

swap函数

这里就不过多介绍了,懂得都懂


2.5  空间关系

 

三、迭代器失效问题

vector底层就是一个指针,vector的迭代器就是原生态指针T*

因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)

3.1  使用迭代器区间来构造

在顺序表中存放string类型:

string str("abcdefg");
vector<string> vv(str.begin(),str.end());

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

四、深浅拷贝问题


  • resize开辟有效数据空间并初始化时不能使用memset初始化,因为mem系列函数是按字节去处理
  • reserve开辟容量空间时开辟的新空间不能使用memcpy把旧空间的数据拷贝过去,要使用循环赋值过去,因为memcpy是浅拷贝,浅拷贝最后会导致释放旧空间新空间的指针指向一块已被释放的空间,造成程序崩溃

代码测试:

Vector(const Vector<T>& v)
{
	assert(v._start && v._finish && v._endofsto);
	_start = new T[v.capacity()];//给size或capacity都可以
	memcpy(_start, v._start, sizeof(T) * v.size());
}

 解决办法:

Vector(const Vector<T>& v)
{
	assert(v._start && v._finish && v._endofsto);
	_start = new T[v.capacity()];//给size或capacity都可以
	//memcpy(_start, v._start, sizeof(T) * v.size()); //使用memcpy时,数组是二维数组会发生问题
	for (size_t i = 0; i < size(); i++)
	{
		_start[i] = v._start[i];
		_finish = _start + v.size();
	}
	_endofsto = _start + v.capacity();
}

、二维数组的开辟和图解

song::vector<song::vector> vv(n); 构造一个vv动态二维数组,vv中总共有n个元素,每个元素都是vector类型的,每行没有包含任何元素,如果n为5时如下所示


代码总结:

#pragma once
#include<iostream>
#include<vector>
#include<assert.h>
#include<list>

using namespace std;

template<class T>
class Vector
{
public:
	typedef T* iterator;
	typedef const T* const_iterator;

	void swap(Vector<T>& v)
	{
		std::swap(_start, v._start);
		std::swap(_finish, v._finish);
		std::swap(_endofsto, v._endofsto);
	}

	iterator begin()
	{
		return _start;
	}

	const_iterator begin()const
	{
		return _start;
	}

	iterator end()
	{
		return _finish;
	}

	const_iterator end()const
	{
		return _finish;
	}

	Vector()
		:_start(nullptr)
		, _finish(nullptr)
		, _endofsto(nullptr)
	{

	}

	template<class InputIterator>
	Vector(InputIterator first, InputIterator last)//有迭代器区间的构造
		:_start(nullptr)
		, _finish(nullptr)
		, _endofsto(nullptr)
	{
		while (first != last)
		{
			push_back(*first);
			first++;
		}
	}

	//这里将size_t改为int可以解决间接寻址的错误,但是库中使用的是size_t
	Vector(int n, const T& val = T())//构造函数:插入n个val,T()是匿名对象的缺省,调用默认构造函数
		:_start(nullptr)
		, _finish(nullptr)
		, _endofsto(nullptr)
	{
		reserve(n);
		for (size_t i = 0; i < n; i++)
		{
			push_back(val);
		}
	}

	~Vector()
	{
		delete[] _start;
		_start = _finish = _endofsto = nullptr;
	}

	/*Vector(const Vector<T>& v)
		:_start(nullptr)
		,_finish(nullptr)
		,_endofsto(nullptr)
	{
		reserve(v.size());
		for (const auto& e : v)
		{
			push_back(e);
		}
	}*/

	Vector(const Vector<T>& v)
	{
		assert(v._start && v._finish && v._endofsto);
		_start = new T[v.capacity()];//给size或capacity都可以
		memcpy(_start, v._start, sizeof(T) * v.size()); //使用memcpy时,数组是二维数组会发生问题
		/*for (size_t i = 0; i < size(); i++)
		{
			_start[i] = v._start[i];
			_finish = _start + v.size();
		}
		_endofsto = _start + v.capacity();*/
	}

	size_t capacity()const
	{
		return _endofsto - _start;
	}

	size_t size()const
	{
		return _finish - _start;
	}

	T& operator[](size_t pos)
	{
		assert(pos < size());
		return _start[pos];
	}

	const T& operator[](size_t pos)const
	{
		assert(pos < size());
		return _start[pos];
	}

	//void reserve(size_t n)
	//{
	//	if (n > capacity())
	//	{
	//		size_t sz = size();
	//		T* tmp = new T[n];
	//		if (_start)
	//		{
	//			memcpy(tmp, _start, sizeof(T) * size());
	//			delete[] _start;
	//		}
	//		_start = tmp;
	//		_finish = _start + sz;
	//		_endofsto = _start + n;//开辟n个空间
	//	}
	//}

	void reserve(size_t n)
	{
		if (n > capacity())
		{
			size_t sz = size();
			T* tmp = new T[n];
			if (_start)
			{
				memcpy(tmp, _start, sizeof(T)*sz);
				/*for (size_t i = 0; i < sz; ++i)
				{
					tmp[i] = _start[i];
				}
				delete[] _start;*/
			}

			_start = tmp;
			_finish = _start + sz;
			_endofsto = _start + n;
		}
	}


	void resize(size_t n, const T& val = T())
	{
		if (n > capacity())//扩容
		{
			reserve(n);
		}
		if (n > size())//初始化,前面的数据不动,后面添加val
		{
			while (_finish < _start + n)
			{
				*_finish = val;
				_finish++;
			}
		}
		else if (n <= size())//删除数据,但不改变原先的数据
		{
			_finish = _start + n;
		}
	}

	void push_back(const T& x)
	{
		/*if (_endofsto == _finish)
		{
			reserve(capacity() == 0 ? 4 : 2 * capacity());
		}
		*_finish = x;
		_finish++;*/
		insert(end(), x);
	}

	void pop_back()
	{
		assert(_finish > _start);
		_finish--;
	}

	iterator insert(iterator pos, const T& x)//若不传入地址或引用,发生扩容后,p位置将不在start和finish之间                               
	{                                    //虽然在函数内部修改了pos,但是pos只是p的一份拷贝
		assert(pos >= _start && pos <= _finish); //库中没有传地址或引用,按照库中的来
		if (_finish == _endofsto)
		{
			size_t len = pos - _start;
			reserve(capacity() == 0 ? 4 : 2 * capacity());
			pos = _start + len;//不更新pos位置的话,扩容后,迭代器会失效
		}
		iterator end = _finish - 1;
		while (end >= pos)
		{
			*(end + 1) = *end;
			end--;
		}
		*pos = x;
		_finish++;
		return pos;
	}

	iterator erase(iterator pos)
	{
		assert(pos >= _start && pos < _finish);
		iterator end = pos;
		while (end <= _finish)
		{
			*(end) = *(end + 1);
			end++;
		}
		_finish--;
		return pos;

		//if (size() < capacity() / 2)//库中可能是这样实现的,缩容可能会有迭代器失效的问题
		//{
		//	//缩容
		//}
	}

	Vector<T>& operator=(Vector<T> v)//要交换this和v就不能传引用
	{
		swap(v);//交换后,局部变量v销毁时刚好把*this原先的空间给释放掉了
		return *this;
	}

	T& front()
	{
		assert(size() > 0);
		return *_start;
	}
	T& back()
	{
		assert(size() > 0);
		return *_finish;
	}

private:
	iterator _start;
	iterator _finish;
	iterator _endofsto;
};

以上就是今天的vector实现,喜欢的话请留下您的支持吧,感谢您的收看



 

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

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

相关文章

[SSD综述1.6] SSD固态硬盘参数图文解析_选购固态硬盘就像买衣服?

依公知及经验整理,原创保护,禁止转载。 专栏 《SSD入门到精通系列》 <<<< 返回总目录 <<<< ​ 传统的 HDD 是“马达+磁头+磁盘”的机械结构,而 SSD 则是“闪存介质+主控”的纯半导体芯片存储结构,两者在数据存储介质和读写方式上有着本质区别,这…

S4.2.4.5 Lane Polarity Inversion

一 本章节主讲知识点 1.1 Polarity Inversion 极性反转 1.2 Lane Reversal 通道翻转 二 本章节原文翻译 2.1 极性反转 原文摘录&#xff1a; PCIe 协议规定&#xff0c;必须支持该特性。该特性的目标也是为了简化 PCB 的布线。每个 lane 都包含一组发送&#xff08;Tx&…

Datawhale-AIGC实践

Datawhale-AIGC实践 部署ChatGLM3-6B平台 clone 项目&#xff0c;配置环境 git clone https://github.com/THUDM/ChatGLM3.git cd ChatGLM3 pip install -r requirement.txt修改web_demo.py, web_demo2.py 设置加载模型的路径修改启动代码: demo.queue().launch(shareFalse…

4.6找出字符串中第一个匹配的下标(还是不太会KMP)

算法&#xff1a;用了KMP算法节省时间、空间复杂度 不过代码还是不太会&#xff0c;只能解读正确代码 正确代码&#xff1a; class Solution:def getNext(self, next, s):j -1next[0] jfor i in range(1, len(s)):while j > 0 and s[i] ! s[j1]:j next[j]if s[i] s[j…

uniapp原生插件之安卓SVGA动画原生插件

插件介绍 安卓SVGA插件是原生组件式插件&#xff0c;支持SVGA动画文件格式播放&#xff0c;支持网络地址播放 插件地址 安卓SVGA动画原生插件 - DCloud 插件市场 详细使用文档 uniapp 安卓SVGA动画原生插件 超级福利 uniapp 插件购买超级福利 用法 插件权限 android…

2023年软件系统架构师论文【回忆版】

2023年11月5日&#xff0c;全国计算机等级下半年考试&#xff0c;北京市软件架构师考试其中有个考点在首都经济贸易大学丰台校区&#xff09;&#xff0c;地址&#xff1a;北京市丰台区花乡张家路口121号&#xff08;北门入校&#xff09; 注意&#xff1a;机考的考试时间有所变…

docker镜像使用

一、查看docker版本 docker version docker默认安装目录 /var/lib/docker 目录文件如下&#xff1a; 二、查看下载的镜像 docker images 三、下载镜像 docker pull [OPTIONS] NAME[:TAG|DIGEST] option作用-a, --all-tags拉取所有 tagged 镜像–disable-content-trust…

win10 + cmake3.17 编译 nvtt2.1.0

nvtt下载地址&#xff1a; https://github.com/pps83/nvtt 以下操作的根目录&#xff1a;D:\Depend_3rd_party\nvtt 2.1.0 1. 下载nvtt 2.1.0&#xff0c;解压到根目录&#xff0c;得到 D:\Depend_3rd_party\nvtt 2.1.0\nvidia-texture-tools-2.1.0 2. 创建build文件夹&am…

BO(Business Object)是一种用于表示业务对象的设计模式

BO是 Business Object 的缩写&#xff0c;是一种用于表示业务对象的设计模式。在Java中&#xff0c;BO的主要作用是 封装业务逻辑&#xff0c;实现业务流程的可重用性和可维护性。 BO主要有以下几个作用&#xff1a; 实现业务逻辑的封装&#xff1a;将业务逻辑封装在BO对象中&a…

LVGL_多界面切换

LVGL_多界面切换 1、创建多个界面&#xff08;create_page1();&#xff09; 2、加载一个界面显示&#xff08;lv_scr_load(page1);&#xff09; 3、切换不同界面显示&#xff08;lv_scr_load_anim(page2, LV_SCR_LOAD_ANIM_OVER_LEFT, 300, 0, false);&#xff09; static lv_…

窗口小插件,用于显示当前系统时间,CPU与内存占用率,网络上传下载速度

最近在弄一个小玩意儿&#xff0c;旨在生成一个窗口小插件&#xff0c;用于显示当前系统时间&#xff0c;CPU与内存占用率&#xff0c;网络上传下载速度 初始目标&#xff1a; 生成一个弹窗&#xff0c;窗口置顶弹窗内可以进行设定&#xff0c;勾选想要显示的对应信息&#xf…

【深度学习 AIGC】stable diffusion webUI 使用过程,参数设置,教程,使用方法

文章目录 docker快速启动vae.ckpt或者.safetensorsCFG指数/CFG Scale面部修复/Restore facesRefinerTiled VAEClip Skipprompt提示词怎么写 docker快速启动 如果你想使用docker快速启动这个项目&#xff0c;你可以按下面这么操作&#xff08;显卡支持CUDA11.8&#xff09;。如…

【蓝桥每日一题]-倍增(保姆级教程 篇1)

今天讲一下倍增 目录 题目&#xff1a;忠诚 思路&#xff1a; 题目&#xff1a;国旗计划 思路&#xff1a; 查询迭代类倍增&#xff1a; 本质是一个一个选区间使总长度达到 M,类似凑一个数。而我们会经常用不大于它最大的二的次幂&#xff0c;减去之后&#xff0c;再重复这…

VSCode中的任务什么情况下需要配置多个问题匹配器problemMatcher?多个问题匹配器之间的关系是什么?

☞ ░ 前往老猿Python博客 ░ https://blog.csdn.net/LaoYuanPython 一、简介 在 VS Code 中&#xff0c;tasks.json 文件中的 problemMatcher 字段用于定义如何解析任务输出中的问题&#xff08;错误、警告等&#xff09;。 problemMatcher是一个描述问题匹配器的接口&…

leetCode 416.分割等和子集 + 01背包 + 动态规划 + 记忆化搜索 + 递推 + 空间优化

关于此题我的往期文章&#xff1a; LeetCode 416.分割等和子集&#xff08;动态规划【0-1背包问题】采用一维数组dp:滚动数组&#xff09;_呵呵哒(&#xffe3;▽&#xffe3;)"的博客-CSDN博客https://heheda.blog.csdn.net/article/details/133212716看本期文章时&…

JAVA-软开-常见八股文(2)-数据库相关

1 Drop Delete Truncate三者之间的区别和联系 drop删除整张表&#xff0c;包括表结构和表数据。用法 drop table 表名 truncate表示清空数据&#xff0c;不会删除表结构。truncate table 表名 delete表示删除数据&#xff0c;不会删除表结构。delete from 表名 where 列名 值…

虽然许多人表示对Windows 11的透明任务栏不满,但有时效果还是挺好的

Windows 11支持透明任务栏&#xff0c;这项功能可以在几秒钟内启用&#xff0c;但许多人表示他们对它的工作方式不满意。 在今天的指南中&#xff0c;我们将向你展示如何使用此功能&#xff0c;并通过一些技巧进一步自定义任务栏。 如何在Windows 11中使任务栏透明 使用个性…

【Linux】第十站:git和gdb的基本使用

文章目录 一、git的基本操作1.gitee新建仓库注意事项2.git的安装3.git的克隆4.git的add5.git的commit6.git的push7.git log8.git status9. .gitignore 二、Linux调试器---gdb1.背景2.gdb安装、进入与退出3.list/l4.r/run运行程序5. break/b 打断点6.info/i b 查看断点7.delete/…

如何使用Selenium处理Cookie,今天彻底学会了

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

搜索引擎系统简要分析

目录 一、搜索引擎简单介绍 二、搜索引擎整体架构和工作过程 &#xff08;一&#xff09;整体分析 &#xff08;二&#xff09;爬虫系统 三个基本点 爬虫系统的工作流程 关键考虑因素和挑战 &#xff08;三&#xff09;索引系统 网页处理阶段 预处理阶段 反作弊分析…