[C++随笔录] vector模拟实现

news2025/1/16 16:42:03

vector模拟实现

  • 基本结构
  • 天选之子
    • 构造
    • 拷贝构造
    • 析构
    • operator=
  • 空间
    • reserve
    • resize
    • size && capacity
    • insert
    • push_back
    • erase
    • pop_back
  • 查 && 改
    • swap
    • operator[]
  • 源码

基本结构

// 可以是不同类型, 用类模板
template <class T>
class vector
{
public:
	// 源码里面成员变量的类型用的是迭代器,
	// 所以, 先定义迭代器类型
	typedef T* iterator;
	typedef const T* const_iterator;
	
private:
	iterator _start = nullptr; // 相当于string类中的 _str
	iterator _finish = nullptr; // 相当于string类中的 _size
	iterator _endofstorage = nullptr; // 相当于string类中的 _capacity
}
  1. 成员变量先给缺省值, 便于后面的构造函数 和 拷贝构造函数
  2. 迭代器是 T* , 跟string类中 迭代器是 char* 是一样的道理

天选之子

构造

  1. 默认构造函数
vector()
	:_start(nullptr)
	, _finish(nullptr)
	, _endofstorage(nullptr)
{

}

由于我们给成员变量都给了缺省值, 那么👇👇👇

vector()
{
}

  1. 开空间 + 初始化
    开空间 + 初始化 也是 resize 干的事情, 那么我们就可以直接复用
vector(int n, const T& val = T()) // 缺省值给T的默认构造出来的对象
{
	resize(n, val);
}
  1. 迭代器区间初始化

从上一篇文章得出: 同类型, 不同类型, 数组的区间都可以进行初始化. 迭代器多样化 ⇒ 套用模版
⇒ 进而我们得出: 在模版中可以套用模版

template <class InputIterator>
vector(InputIterator first, InputIterator last)
{
	int n = last - first;
	resize(n);

	int i = 0;
	while (first != last)
	{
		_start[i++] = *first;
		first++;
	}

}

拷贝构造

vector(const vector<T>& tem)
{
	// 找一块新空间 -- 外部深拷贝
	_start = new T[tem.capacity()];
	
	// memcpy(_start, tem._start, tem.capacity); -- 内部浅拷贝, 是错误的
	for (int i = 0; i < tem.size(); i++) // 内部深拷贝
	{
		_start[i] = tem[i];
	}
	
	// 更新size 和 capacity
	_finish = _start + tem.size();
	_endofstorage = _start + tem.capacity();

}
  • 不能使用memcpy来进行拷贝数据的原因 && 外部和内部的深拷贝图示

析构

~vector()
{
	// 释放空间
	delete[] _start;

	// 置空
	_start = _finish = _endofstorage = nullptr;
}

operator=

// 现代写法 -- 传值传参, 巧借拷贝构造
T& operator=(const T tem)
{
	swap(tem);

	return *this;
}

空间

reserve

void reserve(size_t n)
{
	assert(n > 0);

	if (n > capacity())
	{
		size_t sz = size();  // 应该先保存一份sz <== _start会发生变化
		T* tem = new T[n];
		
		// 拷贝数据
		// memcpy(tem._start, _start, n); // 内部浅拷贝
		for (int i = 0; i < size(); i++)
		{
			tem[i] = _start[i]; //调用了T的赋值, 从而实现深拷贝
		}

		// 更新_start
		delete[] _start;
		_start = tem;

		// 更新size 和 capacity
		_finish = _start + sz;
		_endofstorage = _start + n;
	}

}

resize

void resize(size_t n, const T& val = T())
{
	assert(n > 0);
	
	// 缩
	if (size() > n)
	{
		_finish = _start + n;
	}
	// 扩
	else
	{
		reserve(n); // 先开n个空间

		// 从_finish位置开始初始化
		for (int i = size(); i < size() + n; i++)
		{
			_start[i] = val;
		}

		// 改变_finish
		_finish = _finish + n;

	}
}

size && capacity

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

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

insert

void insert(iterator pos, const T& val = T())
{
	assert(pos >= _start && pos <= _finish);

	size_t len = pos - _start; // 在扩容前, 先保存一下pos的相对位置, 以免异地扩容, _start发生变化, 导致pos迭代器失效

	// 是否扩容
	if (_finish == _endofstorage)
	{
		// 考虑到首次插入
		size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapacity);

		pos = _start + len; // 扩容后, 更新pos
	}

	// 往后挪动数据
	iterator end = _finish - 1; 
	while (end >= pos)
	{
		*(end + 1) = *end;
		end--;
	}

	// 插入
	*pos = val;
	_finish = _finish + 1;

}

push_back

void push_back(const T& val = T())
{
	 是否扩容
	//if (_finish == _endofstorage)
	//{
	//	size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
	//	reserve(newcapacity);

	//}

	//*_finish = val;
	//++_finish;
	
	// 复用insert
	insert(_finish, val);
}

erase

iterator erase(iterator pos)
{
	assert(pos >= _start && pos < _finish);
	
	// 往前挪动数据
	iterator it = pos + 1 ;
	while (it != _finish)
	{
		*(it - 1) = *it;
		it++;
	}
	
	// 更新size
	--_finish;

	return pos;
}

pop_back

void pop_back()
{
	// 复用erase, 传参_finish - 1
	erase(--end());

}

查 && 改

swap

void swap(vector<T>& tem)
{
	std::swap(_start, tem._start);
	std::swap(_finish, tem._finish);
	std::swap(_endofstorage, tem._endofstorage);

}

operator[]


T& operator[](size_t n)
{
	return _start[n];
}

const T& operator[](size_t n)const 
{
	return _start[n];
}

源码

#pragma once

#include<assert.h>
#include<iostream>

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

		iterator begin() 
		{
			return _start;
		}

		iterator end() 
		{
			return _finish;
		}

		const_iterator begin()const
		{
			return _start;
		}

		const_iterator end()const
		{
			return _finish;
		}

		vector()
		{

		}

		vector(int n, const T& val = T()) // 缺省值给	T的默认构造出来的对象
		{
			resize(n, val);
		}

		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			int n = last - first;
			resize(n);

			int i = 0;
			while (first != last)
			{
				_start[i++] = *first;
				first++;
			}

		}

		vector(const vector<T>& tem)
		{
			// 找一块新空间 -- 外部深拷贝
			_start = new T[tem.capacity()];

			// memcpy(_start, tem._start, tem.capacity); -- 内部浅拷贝, 是错误的
			for (int i = 0; i < tem.size(); i++) // 内部深拷贝
			{
				_start[i] = tem[i];
			}

			// 更新size 和 capacity
			_finish = _start + tem.size();
			_endofstorage = _start + tem.capacity();

		}

		~vector()
		{
			// 释放空间
			delete[] _start;

			// 置空
			_start = _finish = _endofstorage = nullptr;
		}

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

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

		void reserve(size_t n)
		{
			assert(n > 0);

			if (n > capacity())
			{
				size_t sz = size();  // 应该先保存一份sz <== _start会发生变化
				T* tem = new T[n];

				// 拷贝数据
				// memcpy(tem._start, _start, n); // 内部浅拷贝
				for (int i = 0; i < size(); i++)
				{
					tem[i] = _start[i]; //调用了T的赋值, 从而实现深拷贝
				}

				// 更新_start
				delete[] _start;
				_start = tem;

				// 更新size 和 capacity
				_finish = _start + sz;
				_endofstorage = _start + n;
			}

		}

		void resize(size_t n, const T& val = T())
		{
			assert(n > 0);

			if (size() > n)
			{
				_finish = _start + n;
			}
			else
			{
				reserve(n); // 先开n个空间

				// 从_finish位置开始初始化
				for (int i = size(); i < size() + n; i++)
				{
					_start[i] = val;
				}

				// 改变_finish
				_finish = _finish + n;

			}
		}

		void push_back(const T& val = T())
		{
			 是否扩容
			//if (_finish == _endofstorage)
			//{
			//	size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
			//	reserve(newcapacity);

			//}

			//*_finish = val;
			//++_finish;

			insert(_finish, val);
		}

		void insert(iterator pos, const T& val = T())
		{
			assert(pos >= _start && pos <= _finish);

			size_t len = pos - _start; // 在扩容前, 先保存一下pos的相对位置, 以免异地扩容, _start发生变化, 导致pos迭代器失效

			// 是否扩容
			if (_finish == _endofstorage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);

				pos = _start + len; // 扩容后, 更新pos
			}

			// 往后挪动数据
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				end--;
			}

			// 插入
			*pos = val;
			_finish = _finish + 1;

		}

		T& operator[](size_t n)
		{
			return _start[n];
		}

		const T& operator[](size_t n)const 
		{
			return _start[n];
		}

		void swap(vector<T>& tem)
		{
			std::swap(_start, tem._start);
			std::swap(_finish, tem._finish);
			std::swap(_endofstorage, tem._endofstorage);

		}

		iterator erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);

			iterator it = pos + 1 ;
			while (it != _finish)
			{
				*(it - 1) = *it;
				it++;
			}

			--_finish;

			return pos;
		}
		
		void pop_back()
		{
			// 复用erase, 传参_finish - 1
			erase(--end());
		
		}

		// 现代写法 -- 传值传参, 巧借拷贝构造
		T& operator=(const T tem)
		{
			swap(tem);

			return *this;
		}

	private:
		iterator _start = nullptr; // 相当于string类中的 _str
		iterator _finish = nullptr; // 相当于string类中的 _size
		iterator _endofstorage = nullptr; // 相当于string类中的 _capacity

	};
}


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

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

相关文章

Spring学习笔记1 启示录

写段代码,引出Spring的好处 创建个空工程,然后在工程里建模块 可能是IEAD版本问题,每次建新的空工程,都需要退出重进 设置下maven和Encoding 新建模块 持久层接口 持久层实现类 业务层接口 业务层实现类 控制层(表现层) 建个测试类测试 分析这个程序存在的问题 假设现在新需…

git和github的入门操作

之前因为工作中用的都是SVN版本控制工具&#xff0c;没接触过git和github&#xff0c;现在开始深入自学Django框架技术后&#xff0c;看到官网推荐使用git&#xff0c;然后这两天网上查阅了很多文章教程&#xff0c;学到入门操作需要学习的点&#xff0c;太多的知识点要后面慢慢…

PostgreSQL 数据库实现公网远程连接

文章目录 前言1. 安装postgreSQL2. 本地连接postgreSQL3. Windows 安装 cpolar4. 配置postgreSQL公网地址5. 公网postgreSQL访问6. 固定连接公网地址7. postgreSQL固定地址连接测试 前言 PostgreSQL是一个功能非常强大的关系型数据库管理系统&#xff08;RDBMS&#xff09;,下…

有没有免费的云渲染平台?哪家云渲染平台收费更合理?

&#xfeff;如今&#xff0c;越来越多的设计师开始使用云渲染平台来加快渲染速度并降低成本。许多人都想知道是否有免费的云渲染平台&#xff0c;或者说哪家云渲染平台收费更合理。在本文中&#xff0c;小编将详细介绍这些问题&#xff0c;帮助您更好地了解和选择适合您需求的…

同一份数据全域共享,HashData UnionStore实时性背后的故事

时至今日&#xff0c;数据已经被越来越多的企业视为发展的战略资源&#xff0c;而云数仓则是数据发挥重要价值的关键媒介。云数仓的出现&#xff0c;不仅改变了传统数据仓库的服务模式&#xff0c;更给用户带来了应对海量、新型数据的存储和处理能力&#xff0c;为满足业务现代…

MES管理系统在生产中的应用及智能工厂的构建思路

在当今制造业中&#xff0c;随着信息化技术和智能化的不断发展&#xff0c;MES生产管理系统已成为工厂生产的核心组成部分。MES管理系统不仅能够提高生产效率&#xff0c;还可以优化生产流程&#xff0c;提升产品质量。本文将详细介绍MES管理系统在工厂生产中的应用以及构建智能…

PowerShell切换多个java版本

安装jdk1.8 和 jdk17 下载jdk 前往 oracle官网下载 配置环境变量 变量名 CLASSPATH变量值 .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar效果图&#xff1a; 变量名&#xff08;jdk1.8同理&#xff09; JAVA_HOME17变量值 C:\Program Files\Java\jdk-17效果图&#xff1…

更快,更稳,更智能,科聪穿梭车(RGV)快速构建方案!

随着自动化物流发展&#xff0c;密集存储得到越来越广泛地应用&#xff0c;已经是现代物流的重要组成部分之一。作为密集存储系统中关键设备之一&#xff0c;穿梭车&#xff08;RGV&#xff09;越来越受到大家的重视。 穿梭车&#xff08;RGV&#xff09;是一种智能机器人&…

GB28181协议-SDP详解

SDP协议 SDP全称是Session Description Protocol&#xff0c;翻译过来就是描述会话的协议。主要用于两个会话实体之间的媒体协商。 SDP描述由许多文本行组成&#xff0c;文本行的格式为<类型><值>&#xff0c;表示为keyvalue; SIP负责建立和释放会话&#xff0c…

基于vue3 + ant-design 自定义SVG图标iconfont的解决方案;ant-design加载本地iconfont.js不显示图标问题

基于vue3 ant-design 自定义SVG图标iconfont的解决方案&#xff1b; ant-design加载本地iconfont.js不显示图标问题 一、准备工作 1、首先去阿里巴巴矢量图标库自定义添加自己的图标&#xff1b;网站地址https://www.iconfont.cn/ 整个步骤是&#xff1a;选择图标–添加到项…

人大女王大学金融硕士——人生的每一刻,都是在为自己的明天铺垫

随着社会经济的迅速发展&#xff0c;经济全球化不断扩大。许多学子想要体验到更加多元化的教育&#xff0c;却又不想出国&#xff0c;那么中外合作办学硕士便是最好的方式。作为金融人士的你&#xff0c;不妨看看中国人民大学与加拿大女王大学合办的金融硕士项目&#xff0c;或…

【Verilog教程】3.2 Verilog 时延

关键词&#xff1a;时延&#xff0c; 惯性时延 连续赋值延时语句中的延时&#xff0c;用于控制任意操作数发生变化到语句左端赋予新值之间的时间延时。 时延一般是不可综合的。 寄存器的时延也是可以控制的&#xff0c;这部分在时序控制里加以说明。 连续赋值时延一般可分为…

人源化抗体的改造方式及其优势

抗体是一类能与抗原特异性结合的免疫球蛋白&#xff0c;作为免疫系统中的重要组成部分&#xff0c;在许多疾病的预防和治疗中发挥着重要作用。抗体治疗的最早应用可以追溯到中国人接种“人痘”预防天花的记载算起&#xff0c;国际上一般公认的人痘接种术最早起源于中国公元10世…

创新未来,工信部组建【AI应用工作组】助力人工智能进步

随着人工智能大模型技术的快速发展和成熟&#xff0c;AI应用已经从早期的概念阶段进入了千行百业的实践落地阶段&#xff0c;三百六十行、行行需AI。如今&#xff0c;AI已经成为推动各行各业创新和发展的重要引擎&#xff0c;对经济、社会和文化的发展产生了深远的影响。为了进…

什么是葡萄酒结构,结构型葡萄酒好吗?

葡萄酒爱好者使用许多复杂的术语来描述葡萄酒的味道&#xff0c;有些是不言自明的&#xff0c;有些则有点模糊。如果你不是葡萄酒专家&#xff0c;你可能很难理解这个葡萄酒术语的全部含义。其中一个术语是葡萄酒结构&#xff0c;那么葡萄酒结构是什么意思呢&#xff1f;而结构…

react实现列表滚动组件

1.需求 在开发项目的时候&#xff0c;从服务端获取到数据列表后&#xff0c;展示给用户看&#xff1a;需要实现数据自动滚动效果&#xff0c;怎么实现呢&#xff1f;如下图所示&#xff1a; 2.实现 把上面需要实现的功能写成一个组件&#xff0c;页面直接调用该组件即可&#x…

视频号视频怎么下载(视频号如何下载里面的视频)

根据大家分享出来的视频号如何下载里面的视频的相关提供的下载方案&#xff0c;我们特别总结了多款可以下载视频号视频怎么下载的办法&#xff01; 如果你还不会提取视频号里的视频&#xff0c;赶快来看看视频号里的视频怎么保存到相册的吧&#xff01; 1:视频下载缓存 该方法…

Python中转换IP地址格式的方法

IP地址一般用字符串“XXX.XXX.XXX.XXX”表示。例如&#xff0c;“192.168.147.1”、“127.0.0.1”等。在确定主机IP地址段时&#xff0c;需要将IP地址的每段转换成数字。 1 inet_aton()方法 该方法的使用方法是 socket.inet_aton(ip_string) 其中&#xff0c;参数ip_string…

主机安全技术

主机安全 1、主机分类 类Unix主机 Unix&#xff1a;Solaris&#xff0c;AIXLiunx&#xff1a;Redhat&#xff0c;Centos&#xff0c;SUSE等 Windows主机 Windows server 2012&#xff0c;server 2008等 特殊主机 IBM iseris&#xff0c;大型机等等 2、主机风险 操作系统风…

微信这样的加人方式,既安全又解放双手

在当今竞争激烈的市场环境下&#xff0c;如何高效地管理和运营私域流量成为企业发展的关键。 1.批量自动化加好友的优势 &#xff08;1&#xff09;提高效率&#xff1a;批量自动化添加好友功能可以帮助企业添加大量潜在客户或目标客户。相比手动逐个添加好友&#xff0c;自动…