c++系列之vector类模拟实现

news2024/12/22 20:25:22

在这里插入图片描述

💗 💗 博客:小怡同学
💗 💗 个人简介:编程小萌新
💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞

构造函数

vector()


//_begin表示有效成员的开始
//_finish表示有效成员的大小
//_end表示有效的容积
vector()
	:_begin(nullptr)
	,_finish(nullptr)
	,_end(nullptr)
	{
	}

vector(size_t n, const T& value = T())

//这里不用memcpy拷贝的原因是
//1. memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
//2. 如果拷贝的是内置类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。
//3.内置类型也有拷贝构造
vector(int n, const T& value = T())
			:_begin(nullptr)
			, _finish(nullptr)
			, _end(nullptr)
		{
			_begin = new T[n];
			_finish = _begin + n;
			_end = _begin + n;
			for (int i = 0; i < n; i++)
			{
				*(_begin + i) = value;
			}
			
		}

//便捷写法
/*vector(int n, const T& value = T())
{
	reserve(n);
	for (int i = 0; i < n; i++)
	{
		_begin[i] =  value;
	}
}
vector(int n, const T& value = T())
{
	resize(n,value);
}*/

vector(InputIterator first, InputIterator last)

//迭代器构造
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
	while (first!= last)
	{
		push_back(*first);//尾插
		first++;	
	}
}

vector(vector& v)

//拷贝构造
vector(vector<T>& v)
{
	size_t size = v._finish - v._begin;
	size_t capacity = v. _end - v._begin;
	_begin = new T[capacity];
	for (size_t i = 0; i < size; i++)
	{
		*(_begin + i) = *(v._begin + i);
	}
	_finish = _begin + size;
	_end = _begin + capacity;	
}
//简便写法
vector(vector<T>& v)
{
	vector<T> tmp(v.begin(),v.end());
	swap(tmp);
}

析构函数

~vector()

~vector()
{
	if (_begin)
	{
		delete[] _begin;
		_begin = _end = _finish = nullptr;
	}
}

运算符重载

vector& operator = (vector v)

//赋值拷贝
vector<T>& operator = (vector<T> v)
{
	swap(v);//这里传的是v的拷贝,改变v并不影响原本的对象
	return *this;
}

T& operator[](size_t pos);


T& operator[](size_t pos)
{
	assert(pos >= 0 && pos < size());//pos在有效范围种
	return _begin[pos];
}
//const对象调用
const T& operator[](size_t pos)const
{
	assert(pos >= _begin && pos < _finish);
	return _begin[pos];
}

查询vector容积和大小

size_t size()

size_t capacity()


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

size_t capacity() const
{
	return _end - _begin;
}
size_t size()
{
	return _finish - _begin;
}

size_t capacity()
{
	return _end - _begin;
}

调整vector的容积和大小

void reserve(size_t n)

void resize(size_t n, const T& value = T())


//这里发生扩容之后,原本的_begin,_finish,_end会发生改变,所以扩容之后要更新
void reserve(size_t n)
{
	if(n > capacity())
	{
		size_t oldsize = size();
		T* tmp = new T[n];
		for (size_t i = 0; i < oldsize; i++)
		{
			tmp[i]  = _begin[i];
		}
			delete[] _begin;
			_begin = tmp;
			_finish = tmp +oldsize;
			_end = tmp + n;
		}
}

void resize(size_t n, const T& value = T())
{
	if (n < size())
	{
		_finish = _begin + n;
	}
	else
	{
		if (n > capacity())
		{
			reserve(n);
		}
		while(_finish < _begin + n)
		{
			*(_finish++) = value;
		}
	}
}

修改vector(头插,尾插,插入,删除,交换)

void push_back(const T& x)

void pop_back()

iterator insert(iterator pos, const T& x)

iterator erase(iterator pos)

void swap(vector& v)

void push_back(const T& x)
{
	if (_finish == _end)
	{
		reserve(capacity() == 0? 4: capacity()*2);
	}
		*_finish =  x;
		_finish++;
	}

void pop_back()
{
	assert(_begin != _finish);
	_finish--;
}
//这里会发生迭代器失效问题、
//原因1:如果发生扩容函数里原pos会变成野指针需要及时更新,函数外pos不会改变,所以要返回pos的新指针
//原因2.因为插入数据,原本pos意义改变,所以要及时更新,让pos指向新插入的元素
//正确做法是返回迭代器插入的指针
iterator insert(iterator pos, const T& x)
{
	assert(pos >= _begin && pos <= _finish);
	if (_finish == _end)
	{
		size_t size = pos - _begin;
		reserve(capacity() == 0 ? 4 : capacity() * 2);
		pos = _begin + size;
	}
	iterator end = _finish - 1;
	while (end >= pos)
	{
		*(end +1) = *(end);
		end--;
	}
	*pos = x;
	_finish++;
	return pos;
}
//迭代器失效原因1.erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。
//迭代器失效原因2:erase之后pos位置的意义改变,迭代器所以要更新
//正确做法是返回迭代器下一个的指针
iterator erase(iterator pos)
{
	assert(pos >= _begin && pos <_finish );
	iterator end = pos + 1;
	while (end < _finish)
	{
		*(end - 1) = *(end);
		end++;
	}
	_finish--;
	return pos;
}
void swap(vector<T>& v)
{
	std::swap(_begin,v._begin);
	std::swap(_finish,v._finish);
	std::swap(_end,v._end);
}

vector的迭代器

typedef T* iterator;
typedef const T* const_iterator;

完整代码

namespace zjy
{
	template<class T>
	class vector
	{
		public:
		        
		typedef T* iterator;
		typedef const T* const_iterator;

		iterator begin()
		{
			return _begin;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator cbegin()
		{
			return _begin();
		}

		const_iterator cend() const
		{
			return _finish;
		}



		vector()
			:_begin(nullptr)
			,_finish(nullptr)
			,_end(nullptr)
		{

		}

		vector(int n, const T& value = T())
			:_begin(nullptr)
			, _finish(nullptr)
			, _end(nullptr)
		{
			_begin = new T[n];
			_finish = _begin + n;
			_end = _begin + n;
			for (int i = 0; i < n; i++)
			{
				*(_begin + i) = value;
			}
		}

		//vector(int n, const T& value = T())
		//{
		//	reserve(n);
		//	for (int i = 0; i < n; i++)
		//	{
		//		_begin[i] =  value;
		//	}
		//}
		//vector(int n, const T& value = T())
		//{
		//	resize(n,value);
		//}

		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{

			while (first!= last)
			{
				push_back(*first);
				first++;
				
			}
		}

		vector(vector<T>& v)
		{
			size_t size = v._finish - v._begin;
			size_t capacity = v. _end - v._begin;
			_begin = new T[capacity];
			for (size_t i = 0; i < size; i++)
			{
				*(_begin + i) = *(v._begin + i);
			}
			_finish = _begin + size;
			_end = _begin + capacity;
		}
	//vector(vector<T>& v)
	//{
	//	vector<T> tmp(v.begin(),v.end());
	//	swap(tmp);
	//}

		vector<T>& operator = (vector<T> v)
		{
			swap(v);
			return *this;
		}

		~vector()
		{
			if (_begin)
			{
				delete[] _begin;
				_begin = _end = _finish = nullptr;
			}
		}


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

		size_t capacity() const
		{
			return _end - _begin;
		}

		void reserve(size_t n)
		{
			if(n > capacity())
			{
				size_t oldsize = size();
				T* tmp = new T[n];
				for (size_t i = 0; i < oldsize; i++)
				{
					tmp[i]  = _begin[i];
				}
				delete[] _begin;

				_begin = tmp;
				_finish = tmp +oldsize;
				_end = tmp + n;
			}
		}

		void resize(size_t n, const T& value = T())
		{
			if (n < size())
			{
				_finish = _begin + n;
			}
			else
			{
				if (n > capacity())
				{
					reserve(n);
				}

				while(_finish < _begin + n)
				{
					*(_finish++) = value;

				}
			}
		}

		T& operator[](size_t pos)
		{
			assert(pos >= 0 && pos < size());
			return _begin[pos];
		}

		const T& operator[](size_t pos)const
		{
			assert(pos >= _begin && pos < _finish);
			return _begin[pos];
		}
		void push_back(const T& x)
		{
			if (_finish == _end)
			{
				reserve(capacity() == 0? 4: capacity()*2);
			}
			*_finish =  x;
			_finish++;
		}

		void pop_back()
		{
			assert(_begin != _finish);
			_finish--;
		}

		void swap(vector<T>& v)
		{
			std::swap(_begin,v._begin);
			std::swap(_finish,v._finish);
			std::swap(_end,v._end);
		}

		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _begin && pos <= _finish);
			if (_finish == _end)
			{
				size_t size = pos - _begin;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _begin + size;
			}
			
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end +1) = *(end);
				end--;
			}

			*pos = x;
		
			_finish++;
			return pos;

		}

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

			}
			_finish--;
			return pos;

		}
	private:
		T* _begin = nullptr;
		T* _finish = nullptr;
		T* _end = nullptr;
	};
}

在这里插入图片描述

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

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

相关文章

prometheus监控kafka

一、前言 关于对kafka的监控&#xff0c;要求高的话可以使用kafka-exorter和jmx-exporter一起收集监控数据&#xff0c;要求不高的情况下可以使用kafka-exporter收集监控数据即可 二、部署 kafka-exporter 部署kafka-exporter&#xff0c;我是在k8s集群中部署的 编辑yaml文件…

基于5G工业CPE打造智慧煤矿无人巡检监测应用

煤炭是我国重要的能源资源&#xff0c;对于煤炭的开采和利用也是我国重要的工业产业部分。得益于5G物联网技术的发展普及&#xff0c;煤矿场景也迎来智能化升级&#xff0c;实现了包括智能采掘、智能调度、无人运输、无人巡检等新型应用&#xff0c;极大提升了煤矿采运产业的效…

爬虫批量下载科研论文(SciHub)

系列文章目录 利用 eutils 实现自动下载序列文件 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、获取文献信息二、下载文献PDF文件参考 前言 大家好✨&#xff0c;这里是bio&#x1f996;。…

PHP函数的定义与最简单后门原理

PHP函数的定义与最简单后门原理 文章目录 PHP函数的定义与最简单后门原理函数的定义函数调用的过程变量的范围局部变量全局变量 可变函数动态函数 PHP 最简单后门原理分析 函数的定义 使用function关键字来定义一个函数定义函数的函数名避开关键字形式参数是传递映射的实际参数…

css实现圆形进度条

能用现成组件就用&#xff0c;实现不行再自己写&#xff0c;因为牵扯到上传文件&#xff0c;进度实时出不来&#xff0c;所以只能使用dom元素操作&#xff1b; 1.实现 效果&#xff1a; 上图是100%&#xff0c;如果需要根据百分比显示&#xff0c;我们需要看下代码里面left和…

高通平台GPIO引脚复用指导

高通平台GPIO引脚复用指导 1. 概述1.1 平台有多少个GPIO&#xff1f;1.2 这些GPIO都有哪些可复用的功能&#xff1f; 2. 软件配置2.1 TZ侧GPIO配置2.2 SBL侧GPIO配置2.3 AP侧GPIO配置2.3.1 Linux DTS机制与设备驱动模型概述2.3.2高通平台的pinctrl控制器2.3.2.1 SDX12 CPU pinc…

axios封装以及详细用法

文章目录 axios用法(这里没有封装&#xff0c;下面有封装好的get&#xff0c;post方法&#xff0c;在axios封装里面)get &#xff0c;delete方法post&#xff0c;put方法 axios具体封装axios 具体参数配置 axios用法(这里没有封装&#xff0c;下面有封装好的get&#xff0c;pos…

全球创业浪潮:跨境电商的创新时代

在当今数字化的时代&#xff0c;全球商业局势正在发生深刻的变革&#xff0c;而跨境电商正处于这一变革的前沿。随着全球创业浪潮的崛起&#xff0c;跨境电商行业正在迎来一个充满创新活力的时代。这篇文章将深入探讨跨境电商如何在全球创业浪潮中扮演关键角色&#xff0c;以及…

国际腾讯云自主拼装直播 URL教程!!!

注意事项 创建转码模板 并与播放域名进行 绑定 后&#xff0c;转码配置后的直播流&#xff0c;需将播放地址的 StreamName 拼接为 StreamName_转码模板名称&#xff0c;更多详情请参见 播放配置。 前提条件 已注册腾讯云账号&#xff0c;并开通 腾讯云直播服务。 已在 域名…

Parallels Desktop 19.1.0 pd Mac 虚拟机解决方案

Parallels Desktop 是功能最强大灵活度最高的虚拟化方案&#xff0c;无需重启即可在同一台电脑上随时访问 Windows 和 Mac 两个系统上的众多应用程序。从仅限于 PC 的游戏到生产力软件&#xff0c;Parallels Desktop 都能帮您实现便捷使用。 Parallels Desktop 19.1.0 应用介绍…

云服务器的先驱,亚马逊云科技海外云服务器领军者

随着第三次工业革命的发展&#xff0c;移动互联网技术带来的信息技术革命为我们的生活带来了极大的便捷。其中&#xff0c;不少优秀的云服务器产品发挥了不可低估的作用&#xff0c;你或许听说过亚马逊云科技、谷歌GCP、IBM Cloud等优秀的海外云服务器。那么云服务器有哪些&…

【k8s】kubeadm安装k8s集群

一、环境部署 master192.168.88.10docker、kubeadm、kubelet、kubectl、flannelnode01192.168.88.20docker、kubeadm、kubelet、kubectl、flannelnode02192.168.88.30docker、kubeadm、kubelet、kubectl、flannelhub.lp.com192.168.88.40 docker、docker-compose harbor-offli…

SDL窗口创建以及简单显示(1)

项目创建步骤 1. 使用Qt Creator创建一个C项目 2. 将SDL库文件放到源文件目录下 在项目pro文件中添加库文件 win32{INCLUDEPATH $$PWD/SDL2-2.0.10/includeLIBS $$PWD/SDL2-2.0.10/lib/x86/SDL2.lib } 使用SDL创建一个窗口 #include <stdio.h>#include <SDL.h>…

HarmonyOS开发:探索组件化模式开发

前言 组件化一直是移动端比较流行的开发方式&#xff0c;有着编译运行快&#xff0c;业务逻辑分明&#xff0c;任务划分清晰等优点&#xff0c;针对Android端的组件化&#xff0c;之前有比较系统的总结过相关文章&#xff0c;感兴趣的朋友&#xff0c;可以查看&#xff0c;点击…

java后端返回给前端不为空的属性

问题背景&#xff1a; 目前遇到的一个问题。一个对象里面定义了数组、集合、和字符串属性等&#xff0c;但是返回给前端的时候数组和集合都是空的&#xff0c;前端接收到的是“” 一个空字符。然后保存的时候又把空字符传给后端&#xff0c;出现了数据结构不匹配导致报错。 解…

二、【常用的几种抠图方式一】

文章目录 选框抠图快速选择工具抠图魔棒工具抠图对象选择工具抠图套索工具抠图多边形套索工具抠图磁性套索工具抠图 选框抠图 选框工具抠图适合规则的图形&#xff0c;如下图先使用选框工具框出对象的图轮廓&#xff0c;然后再选择并遮住在里边擦出图形的边缘&#xff0c;根据…

Hi3516DV500部署paddle版型分析模型记录

原版模型测试并导出onnx paddle 版面分析-> https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.7/ppstructure/layout/README_ch.md 测试 python3 deploy/python/infer.py \ --model_dirmodel/picodet_lcnet_x1_0_fgd_layout_cdla_infer/ \ --image_fil…

Openssl数据安全传输平台011:base64的使用

文章目录 1 base641.1 概念1.2 应用场景 2 base64 算法 &#xff08;重要&#xff09;3 openssl 中base64的使用3.1 BIO 操作3.2 base64 编码 -> bio链的写操作3.3 base64 解码 -> bio链的读操作 1 base64 1.1 概念 Base64是一种基于64个可打印字符来表示二进制数据的表…

CTF-Web(3)文件上传漏洞

笔记目录 CTF-Web(2)SQL注入CTF-Web(3)文件上传漏洞 1.WebShell介绍 (1)一句话木马定义 一种网页后门&#xff0c;以asp、php、jsp等网页文件形式存在的一种命令执行环境&#xff0c;而 一句话木马往往只有一行WebShell代码。 作用&#xff1a; 攻击获得网站控制权限 查看、修改…

p5.js 状态管理

本文简介 带尬猴&#xff0c;我是德育处主任 原生 canvas 提供了 save() 和 restore() 两个方法去管理画布状态。p5.js 作为一个 canvas 库&#xff0c;也理所当然的提供了状态管理的方法。在 p5.js 里这两个方法叫 push() 和 pop()。 本文主要讲解 p5.js 的 push() 和 pop()…