自定义vector的实现

news2024/9/27 19:18:29

实现前需要思考的一个问题

为什么需要将空间的申请与对象的构建分开

查看vector的模板参数时可以看到其有第三个参数是空间适配器allocator,查找其对外提供的成员函数不难发现它的实现逻辑是将空间的申请与对象的构建分开的,为什么呢?不弄清楚这个问题显然我们是无法自定义实现一个vector的。
在这里插入图片描述

我们都知道,对于vector而言,其有一个预留空间,函数是reserve。

这是因为STL中存放的是大量元素,如果每次创建一个对象就申请一次空间,这样的话效率非常低下。所以可以直接一次性申请大片空间,然后在申请的空间上进行对象的构建,这样效率更快。

代码实现

#include <iostream>
#include <memory>
#include <algorithm>

using namespace std;

template<typename T>
class Vector{
	public:
		typedef T* iterator; //让我们写的这个类型也能通过迭代器进行访问
		Vector()
		:_start(nullptr)
		 ,_finish(nullptr)
		 ,_end_of_storage(nullptr)
		{
			
		}
		~Vector();
		void push_back(const T& value);
		void pop_back();
		int size() const;
		int capacity() const;

		//迭代器指针
		iterator begin(){
			return _start;
		}

		iterator end(){
			return _finish;
		}
	private:
		void reallocate();//重新分配内存,动态扩容要用的
	private:
		//进行空间申请与释放,以及对象构建与销毁的类
		static std::allocator<T> _alloc;

		T* _start;          //指向数组中的第一个元素
		T* _finish;         //指向最后一个实际元素之后的那个元素
		T* _end_of_storage; //指向数组本身之后的位置
};

//静态成员必须在类外进行初始化
template <typename T>
std::allocator<T> Vector<T>::_alloc;

//重新分配内存,动态扩容要用的
template <typename T>
void Vector<T>::reallocate(){
	//1、获取新空间大小
	//先存下来原来的容量
	int oldCapacity = capacity();
	//然后再将新的空间按两倍的标准进行扩容
	//如果oldCapacity为0,那么新空间大小为1,否则就按两倍扩容
	int newCapacity = 2 * oldCapacity > 0 ? 2*oldCapacity : 1;
	//2、申请新的对应大小的空间
	T* _ptmp = _alloc.allocate(newCapacity);
	//将老空间里面的元素拷贝到新的空间里面来
	if(_start){//判断老空间里面是否存在元素
		//若有数据,那么执行拷贝
		//copy(_start,_finish,_ptmp); 这个函数有缺陷
		//我们让其在未初始化的空间上拷贝对象
		uninitialized_copy(_start, _finish, _ptmp);
		//拷贝完先执行销毁对象的操作
		while(_finish != _start){
			//老的空间上的对象一个个进行销毁
			_alloc.destroy(--_finish);
		}
		//然后销毁老的空间,也就是回收老的空间
		_alloc.deallocate(_start,oldCapacity);
	}
	//三个指针之前是指向老的空间,然后扩容之后需要将三个指针与新的空间产生联系
	_start = _ptmp;
	_finish = _start + oldCapacity;
	_end_of_storage = _start + newCapacity;
}

template <typename T>
Vector<T>::~Vector(){
	if(_start){
		while(_finish!=_start){
			_alloc.destroy(--_finish);
		}
		_alloc.deallocate(_start,capacity());
	}
}

//插入元素
template <typename T>
void Vector<T>::push_back(const T& value){
	//首先判断vector是不是满的
	if(size() == capacity()){
		//如果满了,那么扩容
		reallocate();
	}
	//否则没满
	//那么当小于容量大小的时候,往vector里面送值
	if(size() < capacity()){
		//把新的value对象送到vector的末尾
		//然后_finish++继续指到最后一个实际元素的下一个位置
		_alloc.construct(_finish++,value);
	}
}

template <typename T>
void Vector<T>::pop_back(){
	//判断是否为空,不为空才删除一个末尾元素
	if(size() > 0){
		//_finish先减减来到实际元素的位置然后再执行删除
		_alloc.destroy(--_finish);
	}
}

//记录元素个数
template <typename T>
int Vector<T>::size() const{
	//因为指针是被STL的迭代器封装过的,
	//所以直接进行四则运算就可以得到正常的数值
	return _finish - _start;
}

//记录容量
template <typename T>
int Vector<T>::capacity() const{
	return _end_of_storage - _start;
}

template <typename Container>
void printCapacity(const Container& con){
	cout << "con.size()" << con.size()  << endl;
	cout << "con.capacity()" << con.capacity() << endl;
}

void test(){
	Vector<int> number;
	printCapacity(number);

	cout << endl;

	number.push_back(1);
	printCapacity(number);

	cout << endl;
	number.push_back(2);
	printCapacity(number);

	cout << endl;
	number.push_back(3);
	printCapacity(number);

	cout << endl;
	number.push_back(4);
	printCapacity(number);

	cout << endl;
	number.push_back(5);
	printCapacity(number);

	for(auto& elem : number){
		cout << elem << " ";
	}
	cout << endl;
}

int main(){
	test();
	return 0;
}

总结

其实根据vector的源码可以大概实现上面的效果,真正复杂的位置是空间配置器类alloc的实现,上述代码中我们是直接调用的该类的各种API。

如果有时间的话其实可以好好研读一下alloc的源码,看它是如何为我们的容器分配空间和回收空间的,最好是读一读《STL源码剖析》这本书,会对STL有更深刻的体会。

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

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

相关文章

云畅科技技术中心被认定为湖南省省级企业技术中心

近日&#xff0c;湖南省工业和信息化厅公布《2023年第二批湖南省省级企业技术中心(第29批)》&#xff0c;云畅科技技术中心作为研发设计型代表入选。 省级企业技术中心是强化企业技术创新主体地位&#xff0c;增强企业自主创新能力&#xff0c;推动工业企业高质量发展的一个重要…

搬运5款帮你优化电脑的小工具软件

​ 你想让你的电脑更好用吗&#xff1f;这里有五款电脑软件可以帮你&#xff0c;它们可以让你的电脑更高效、美观、安全&#xff0c;快来看看吧&#xff01; 1.窗口管理——MaxMax ​ MaxMax是一款窗口管理软件&#xff0c;可以让你自定义窗口的最大化行为&#xff0c;避免窗…

STC8H8K蓝牙智能巡线小车——2. 点亮左右转弯灯与危险报警灯

任务调用示例 RTX 51 TNY 可做多任务调度&#xff0c;API较为简单。 /* 接口API */// 创建任务 extern unsigned char os_create_task (unsigned char task_id); // 结束任务 extern unsigned char os_delete_task (unsigned char task_id);// 等待 extern unsig…

Ubuntu20.04下A-LOAM配置安装及测试教程(包含报错问题踩坑)

参考文章&#xff1a; ubuntu20.04下ros运行A-LOAM Ubuntu20.04下运行LOAM系列&#xff1a;A-LOAM、LeGO-LOAM、SC-LeGO-LOAM、LIO-SAM 和 LVI-SAM 需要学习源码的同学可以下载LOAM论文 LOAM论文链接 1.需要安装的库文件 1.1Eigen 3.3 可以直接使用apt命令安装&#xff0c;或…

C#,字符串匹配(模式搜索)AC(Aho Corasick)算法的源代码

Aho-Corasick算法简称AC算法&#xff0c;也称为AC自动机(Aho-Corasick)算法&#xff0c;1975年产生于贝尔实验室&#xff08;The Bell Labs&#xff09;&#xff0c;是一种用于解决多模式字符串匹配的经典算法之一。 the Bell Lab 本文的运行效果&#xff1a; AC算法以模式树…

Android 13.0仿ios的hotseat效果修改hotseat样式

1.概述 在13.0系统产品rom定制化开发中,在项目需求的需要,系统原生Launcher的布局样式很一般,所以需要重新设计ui对布局样式做调整,产品在看到 ios的hotseat效果觉得特别美观,所以要仿ios一样不需要横屏铺满的效果 居中显示就行了,所以就要看hotseat的具体布局显示了 效…

Docker部署Traefik结合内网穿透远程访问Dashboard界面

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…

『 C++ 』AVL树详解 ( 万字 )

&#x1f988;STL容器类型 在STL的容器中,分为几种容器: 序列式容器&#xff08;Sequence Containers&#xff09;: 这些容器以线性顺序存储元素&#xff0c;保留了元素的插入顺序。 支持随机访问&#xff0c;因此可以使用索引或迭代器快速访问任何位置的元素。 主要的序列式…

tensorflow报错: DNN library is no found

错误描述 如上图在执行程序的时候&#xff0c;会出现 DNN library is no found 的报错 解决办法 这个错误基本上说明你安装的 cudnn有问题&#xff0c;或者没有安装这个工具。 首先检测一下你是否安装了 cudnn 进入CUDA_HOME下&#xff0c;也就是进入你的cuda的驱动的安装目…

【Leetcode 78】子集 —— 回溯法

78. 子集 给你一个整数数组nums&#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1],[2],[…

记ubuntu2004通过NetworkManager修改网络的优先级

这里写自定义目录标题 前言步骤 前言 起因在于万恶的校园网&#xff0c;突然台式有线死活没法认证&#xff08;感觉是IP冲突了&#xff1f;另外一台电脑同样的系统就没有问题&#xff0c;连路由器WIFI也是可以的&#xff0c;路由器设置的是桥接模式&#xff0c;有没有大佬提供…

欧盟产品安全新规来袭,亚马逊发出紧急提醒(GPSR)要求

欧盟产品安全新规来袭&#xff0c;亚马逊发出紧急提醒&#xff08;GPSR&#xff09;要求 一、发布新规 这世界上唯一不变的事&#xff0c;或许就是变化本身。 在跨境电商领域&#xff0c;这个道理再次得到验证。近日&#xff0c;不少卖家都收到了一封来自亚马逊的通知。通知中…

德语B2 SampleAcademy

德语B2 SampleAcademy 一, Zweigliedrige Konnektion1, entweder... oder2, nicht nur... sondern auch3,sowohl... als auch4,einerseits... andererseits5, zwar...aber6, weder...noch7,je...desto/umso 一, Zweigliedrige Konnektion discontinuous conjunctions 1,…

图解python | 基础数据类型

1.Python变量类型 Python基本数据类型一般分为6种&#xff1a;数值&#xff08;Numbers&#xff09;、字符串&#xff08;String&#xff09;、列表&#xff08;List&#xff09;、元组&#xff08;Tuple&#xff09;、字典&#xff08;Dictionary&#xff09;、集合&#xff…

记一个有关 Vuetify 组件遇到的一些问题

Vuetify 官网地址 所有Vuetify 组件 — Vuetify 1、Combobox使用对象数组 Combobox 组合框 — Vuetify items数据使用对象数组时&#xff0c;默认选中的是整个对象&#xff0c;要对数据进行处理 <v-comboboxv-model"defaultInfo.variableKey":rules"rules…

基于Springboot的善筹网(众筹网-有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的善筹网(众筹网-有报告)。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring S…

华为云优惠券介绍、种类、领取入口及使用教程

华为云作为国内领先的云服务提供商&#xff0c;为了吸引用户&#xff0c;经常推出各种优惠活动&#xff0c;其中就包括华为云优惠券。通过领取和使用优惠券&#xff0c;可以降低用户上云成本&#xff0c;提升用户上云的使用体验。本文将详细介绍华为云的优惠券&#xff0c;包括…

Pandas.DataFrame.loc[ ] 筛选数据-标签法 详解 含代码 含测试数据集 随Pandas版本持续更新

关于Pandas版本&#xff1a; 本文基于 pandas2.1.2 编写。 关于本文内容更新&#xff1a; 随着pandas的stable版本更迭&#xff0c;本文持续更新&#xff0c;不断完善补充。 Pandas稳定版更新及变动内容整合专题&#xff1a; Pandas稳定版更新及变动迭持续更新。 Pandas API参…

京东年度数据报告-2023全年度笔记本十大热门品牌销量(销额)榜单

2023年度&#xff0c;在电脑办公市场整体销售下滑的环境下&#xff0c;笔记本市场的整体销售也不景气。 根据鲸参谋平台的数据显示&#xff0c;京东平台上笔记本的年度销量为650万&#xff0c;同比下滑约16%&#xff1b;销售额约为330亿&#xff0c;同比下滑约19%。同时&#…

【网络取证篇】Windows终端无法使用ping命令解决方法

【网络取证篇】Windows终端无法使用ping命令解决方法 以Ping命令为例&#xff0c;最近遇到ping命令无法使用的情况&#xff0c;很多情况都是操作系统"环境变量"被改变或没有正确配置导致—【蘇小沐】 目录 1、实验环境&#xff08;一&#xff09;无法ping命令 &a…