自定义vector的实现

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

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

查看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.mzph.cn/news/625242.shtml

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

相关文章

SpringBoot异常处理(Whitelabel Error Page和自定义全局异常处理页面)和整合ajax异常处理

SpringBoot异常处理&#xff08;Whitelabel Error Page和自定义全局异常处理页面&#xff09;和整合ajax异常处理 1、springboot自带的异常处理页面Whitelabel Error Page SpringBoot默认的处理异常的机制&#xff1a;SpringBoot 默认的已经提供了一套处理异常的机制。一旦程…

MongoDB 索引管理

文章目录 前言1. 术语介绍1.1 index / key1.2 Coverd Query1.3 IXSCAN / COLLSCAN1.4 Selectivity1.5 Index Prefix 2. 索引原理3. 索引的维护3.1 创建索引语法3.2 单字段索引3.3 多字段复合索引3.4 数组的多列索引3.5 全文索引3.6 Hash 索引3.7 TTL 索引3.8 删除索引3.9 后台创…

基于springboot书籍学习平台源码和论文

首先,论文一开始便是清楚的论述了平台的研究内容。其次,剖析平台需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确平台的需求。然后在明白了平台的需求基础上需要进一步地设计平台,主要包罗软件架构模式、整体功能模块、数据库设计。本项…

MongoDB安装与基本使用

一、简介 1.1 Mongodb 是什么 MongoDB 是一个基于分布式文件存储的数据库&#xff0c;官方地址 https://www.mongodb.com/ 1.2 数据库是什么 数据库&#xff08; DataBase &#xff09;是按照数据结构来组织、存储和管理数据的 应用程序 1.3 数据库的作用 数据库的…

创建React步骤

确保电脑已经安装了node.js以后&#xff0c;打开终端进入目标文件夹 cd xxx(文件夹 npx create-react-app react01(替换为你自己的react名称) 可能会出现是否安装xxx,输入y即可 没有报错信息后&#xff0c;输入 cd react01 npm start 会自动跳转到react界面&#xff0c;就…

翻译: Streamlit从入门到精通 部署一个机器学习应用程序 四

Streamlit从入门到精通 系列&#xff1a; 翻译: Streamlit从入门到精通 基础控件 一翻译: Streamlit从入门到精通 显示图表Graphs 地图Map 主题Themes 二翻译: Streamlit从入门到精通 构建一个机器学习应用程序 三 1. 5. 如何部署一个Streamlit应用 部署是将应用程序从开发…

Linux操作系统——重定向与缓冲区

1.理解一下struct file内核对象 上一篇文章&#xff08;文件详解&#xff09;我们一直在谈&#xff0c;一个文件要被访问就必须要先被打开&#xff0c;打开之前就必须要先把文件加载到内存&#xff0c;同时呢我们的操作系统为了管理文件也会为我们的文件创建相对应的struct fi…

数据库多表查询练习题

二、多表查询 1. 创建 student 和 score 表 CREATE TABLE student ( id INT ( 10 ) NOT NULL UNIQUE PRIMARY KEY , name VARCHAR ( 20 ) NOT NULL , sex VARCHAR ( 4 ) , birth YEAR , department VARCHAR ( 20 ) , address VARCHAR ( 50 ) ); 创建 s…

Qt6入门教程 6:Qt元对象系统

目录 一.什么是Qt元对象系统&#xff1f; 二.编译时Qt Creator偷摸做了哪些事情&#xff1f; 1.uic 2.rcc 3.moc 一.什么是Qt元对象系统&#xff1f; Qt中的元对象系统&#xff08;Meta-Object System&#xff09;提供了对象间通信的信号和槽机制、运行时类型信息和动态属…

uniCloud + uView 上传图片,删除图片(含u-upload 组件的使用)

上传图片 <u-upload imageModeaspectFit height"250" :maxCount1 :fileList"fileList" afterRead"uploadOK" delete"delPic"> </u-upload>::v-deep .u-upload__button {width: 100% !important; }::v-deep .u-upload__wra…

基于JAVA+SSM框架开发的志愿者服务管理系统设计与实现【附源码】

&#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系统 &#x1f4dd; &#x1f680;&#x1f680;&#x1f6…

RK3568笔记九: DRM显示摄像头

若该文为原创文章&#xff0c;转载请注明原文出处。 一、介绍 学习DRM的目的是想做类似NVR显示多路实时流&#xff0c;通过勇哥&#xff08;Marc)的指导&#xff0c;大概流程是通过Zlmedia拉流&#xff0c;RK3568的MPP解码,DRM显示&#xff0c;可以使用HDMI或DIS屏幕&#xf…

ssm+vue的物流配送人员车辆调度管理系统的设计与实现(有报告)。Javaee项目,ssm vue前后端分离项项目。

演示视频&#xff1a; ssmvue的物流配送人员车辆调度管理系统的设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&…

【C++干货铺】会旋转的二叉树——AVLTree

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 前言 AVL树 AVL树的概念 AVL树结点的定义 AVL树的插入 寻找插入结点的位置 修改平衡因子 AVL树的旋转 右单旋 左单旋 先右旋再左旋 先左旋再右旋 AVL树…

Kubernetes (十三) 存储——持久卷-动静态分配

一. 简介 二. NFS持久化存储步骤&#xff08;静态分配&#xff09; 1. 集群外…

数字信号处理教程学习笔记1-第2章时域中的离散信号和系统

信号处理的任务示意方框图 模拟信号和数字信号分别是啥样的,有啥区别

freetos day1

作业&#xff1a;使用计数型信号量设计&#xff1a;生产者和消费者模型 总结今天学习的API函数&#xff0c;写出函数参数和返回值的意思&#xff0c;并且说明函数功能 1 2 3

如何结合主从复制,不停服情况下解决分库分表

首先我们要知道主从复制和分库分表两个概念&#xff0c;在此基础上可以将问题分为几个阶段来执行&#xff0c;参考了公众号 双写读老 双写双读 写新读新

WEB 3D技术 three.js 3D贺卡(1) 搭建基本项目环境

好 今天 我也是在网上学的 带着大家一起来做个3D贺卡 首先 我们要创建一个vue3的项目、 先创建一个文件夹 装我们的项目 终端执行 vue create 项目名称 例如 我的名字想叫 greetingCards 就是 vue create greetingcards因为这个名录 里面是全部都小写的 然后 下面选择 vue3 …

代码随想录算法训练营Day21| 93.复原IP地址、78.子集、90.子集||

LeetCode 93 复原 IP 地址 本题思路&#xff1a;最重要的是想到一个收集结果的条件&#xff0c;也就是终止条件。 当 . 的个数达到三个时候&#xff0c;并且&#xff0c;判断最后剩余的是否符合要求&#xff0c;如果符合&#xff0c;说明整个ip地址可以&#xff0c;就加入到结…