C++模拟实现——vector

一、成员变量

成员变量由三个模板指针构成:

_start : 指向开头位置

_finish : 指向数据结束的地方

_end_of_storage : 指向空间结束的位置

二、基本指标

实现vector的基本思路和顺序表相同,因此会频繁的需要用到数据大小、容量大小这些指标,因此优先提高这两个接口,方便后续复用。

		//常用指标size_t size()const{return _finish - _start;}size_t capacity()const{return _end_of_storage - _start;}bool empty()const //判空{return _start == _finish;}

三、迭代器

vector的迭代器,由于物理空间上连续,因此可以直接使用原生指针去实现。

		typedef T* iterator;typedef const T* con_iterator;//迭代器iterator begin(){return _start;}iterator end(){return _finish;}con_iterator begin()const{return _start;}con_iterator end()const{return _finish;}

四、构造与析构

1.构造函数

(一)、默认构造函数

只需要完成初始化的任务即可,将三个指针初始化为空指针即可

		vector():_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){}

(二)构造函数——一次性构造多个值

这里提供一个能一次性初始化多个值的构造函数,参数一是数据的数量,参数二是数据本身

vector(size_t n,const T& val = T())//这里使用匿名对象去给缺省值,const&能延长匿名对象的生命周期:_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){if(n > capacity()){reserve(n);}for(size_t i =0;i<n;i++){push_back(val);}}//函数重载,避免vector<int>(5,10)的情况,被默认到两个迭代器的位置vector(int n,const T& val = T()):_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){if(n > capacity()){reserve(n);}for(int i =0;i<n;i++){push_back(val);}}

这里要构成函数重载的原因是为了避免特殊情况下,匹配错误的问题,例如int类型的构造时,若没有第二个函数重载,会被默认匹配到两个迭代器构造中

(三)构造函数——用迭代器区间去构造

这里提供的是用任意类型的迭代器区间去完成构造初始化,因此用使用函数模板

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

(四)拷贝构造

拷贝构造可以复用迭代器区间构造得到一个临时拷贝的tmp,然后交换即可

        vector(const vector<T>& v):_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){//reserve(v.capacity());//iterator it = begin();//con_iterator vit = v.begin();//while(vit != v.end())//{//	*it++ = *vit++;//}//_finish =_start + v.size();vector<T> tmp(v.begin(),v.end());swap(tmp);}

2.析构函数

		~vector(){delete[] _start;_start = _finish = _end_of_storage = nullptr;}

五、运算符重载

1.operator[ ]

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

2.operator=

		void swap(vector<T>& tmp){std::swap(_start,tmp._start);std::swap(_finish,tmp._finish);std::swap(_end_of_storage,tmp._end_of_storage);}vector<T>& operator=(vector<T> tmp){swap(tmp);return *this;}

重点:关于深浅拷贝的问题

在reserve的实现中,为什么用memcpy是浅拷贝,而使用while逐一赋值就不是浅拷贝了呢?

例如在vector<vector<int>>类型去调用reserve时,while中*it指代的其实是vector<int>类型,为什么赋值操作可以使得浅拷贝变成深拷贝呢?这个与赋值重载的实现有关

赋值实现如上,深拷贝的完成实际上是在传参时,系统对赋值操作右值进行了深拷贝,并赋值给tmp,空间也是在此时开辟的,然后在使用交换函数,对这一块临时拷贝的空间,转移到赋值操作左值上,在函数结束后对tmp进行销毁,实际上是对原本赋值左操作数的空间进行销毁,并且在此过程中成功完成了深拷贝

六、空间管理

1.reserve

        void reserve(size_t n){if(n > capacity()){size_t sz = size();iterator tmp = new T[n];if(_start)//如果扩容前有数据,则需要拷贝数据{//不能使用浅拷贝//memcpy(tmp,_start,sizeof(T)*size());for(size_t i = 0;i<size();i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}

2.resize

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

七、增删操作

1.insert

优先实现insert,其他的增加操作即可对其进行复用

		iterator insert(iterator pos,const T& val){assert(pos>=_start);assert(pos<=_finish);if(_finish == _end_of_storage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity()*2);pos = _start + len;//更新pos,避免迭代器失效}iterator end = _finish-1;while(end >=pos){*(end+1) = *end;end--;}*pos = val;_finish++;return pos;}

2.erase

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

八、本章重点

1.迭代器失效问题

在涉及对空间进行操作时,迭代器会出现失效的问题,例如reserve、resize操作,会存在扩容问题,而迭代器指向的空间在经过扩容后,未必还是原先的数据,因此会失效

同时insert、push_back、erase等操作也涉及到对空间的操作,因此也是存在迭代器失效的问题

解决迭代器失效的办法:使用后重新赋值

2.关于vector的深拷贝

由于vector内可以多层嵌套不同容器,因此在对于深浅拷贝的问题上更加的复杂,可以对赋值运算符进行重载,利用形参对实参的拷贝去解决深浅拷贝的问题。

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

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

相关文章

竞赛选题 深度学习YOLO安检管制物品识别与检测 - python opencv

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络4 Yolov55 模型训练6 实现效果7 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习YOLO安检管制误判识别与检测 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&…

ChatGPT DALL-E 3的系统提示词大全

每当给出图像的描述时&#xff0c;使用dalle来创建图像&#xff0c;然后用纯文本总结用于生成图像的提示。如果用户没有要求创建特定数量的图像&#xff0c;默认创建四个标题&#xff0c;这些标题应尽可能多样化。发送给Dalle的所有标题都必须遵循以下策略&#xff1a;1.如果描…

KingBase用户与角色及对象访问权限(Kylin)

用户与角色 角色的概念 将一组具有相同权限的用户组织在一起&#xff0c;这一组具有相同权限的用户就称为角色&#xff08;Role&#xff09;角色在生产系统中一般被视为用户组&#xff0c;利用角色对用户进行批量授权 创建用户角色 CREATE USER name WITH [option]授予权限…

python安装、输入输出、注释、中文编码、编码规范等基础语法

一、概述 1、简介 Python的创始人为吉多范罗苏姆&#xff08;Guido van Rossum&#xff09;。1989年的圣诞节期间&#xff0c;Guido开始写Python语言的编译器。Python这个名字&#xff0c;来自Guido所挚爱的电视剧Monty Python’s Flying Circus。他希望这个新的叫做Python的…

C++前缀和算法应用:和至少为 K 的最短子数组的原理、源码及测试用例

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 题目 给你一个整数数组 nums 和一个整数 k &#xff0c;找出 nums 中和至少为 k 的 最短非空子数组 &#xff0c;并返回该子数组的长度。如果不存在这样的 子数组 &a…

《小狗钱钱》阅读笔记(六)

目录 幼儿园最开始的作用不是让小朋友受教育&#xff0c;而是为了提供一个场所让小朋友免于被剥削 弗里德里希福禄贝尔 早期 其实那些有大作为的人&#xff0c;你看到他们的时候&#xff0c;你看&#xff0c;大多小时候都是受到过很多挫折的&#xff0c;我不是说&#xff0c…

小程序setData动态传递key

有些时候可能需要根据key是个变量 比如 let keyName "name" this.setData({keyName :"张三" })本来想将keyName替换为name的&#xff0c;但是小程序只会在data中定义一个key为keyName ,value为“张三”的一条数据。 正确写法为&#xff1a; let keyNam…

Web攻防02-MySQL注入概述MySQL架构注入获取数据

文章目录 SQL注入概述&#xff1a;sql注入的原理&#xff1a;sql注入攻击&#xff1a; MYSQL-Web组成架构MYSQL5.0以上版本&#xff1a;自带的数据库information_schema MYSQL注入流程MYSQL注入查询数据过程查询数据流程靶场案例 MYSQL-SQL跨库注入查询跨库注入&#xff1a;影响…

基础设施SIG月度动态:T-One 社区版调度引擎全量替换至 runnerV2 版本,调度性能平均提升 6.8 倍

基础设施 SIG&#xff08;OpenAnolis Infra SIG&#xff09;目标&#xff1a;负责 OpenAnolis 社区基础设施工程平台的建设&#xff0c;包括官网、Bugzilla、Maillist、ABS、ANAS、CI 门禁以及社区 DevOps 相关的研发工程系统。 01 SIG 整体进展 1.官网 SIG 外链跳转增加确认…

2023年10月中国数据库排行榜:墨天轮榜单前五开新局,金仓、亚信热度攀升

怀鸿鹄之志&#xff0c;展骐骥之跃。 2023年10月的 墨天轮中国数据库流行度排行 火热出炉&#xff0c;本月共有286个数据库参与排名。本月排行榜前十名变动较大&#xff0c;**华为 openGauss 重归探花之位&#xff0c;人大金仓 KingBase 热度上升&#xff0c;亚信 AntDB 进军10…

2023年中国粘度指数改进剂行业需求现状及前景分析[图]

润滑油添加剂指用于提高润滑油使用性能、耐久性及功效&#xff0c;从而增强机械和发动机使用性能的产品&#xff0c;分为单剂和复合剂两大类产品。单剂产品主要是清净剂、分散剂、抗氧抗腐剂、极压抗磨剂、抗氧剂、增粘剂、防锈剂、降凝剂等具有单一特性的添加剂产品&#xff1…

UnitTesting 单元测试

1. 测试分为两种及详细介绍测试书籍: 1.1 Unit Test : 单元测试 - test the business logic in your app : 测试应用中的业务逻辑 1.2 UI Test : 界面测试 - test the UI of your app : 测试应用中的界面 1.3 测试书籍网址:《Testing Swift》 https://www.hackingwithswift.c…

论文阅读之《Kindling the Darkness: A Practical Low-light Image Enhancer》

目录 摘要 介绍 已有方法回顾 普通方法 基于亮度的方法 基于深度学习的方法 基于图像去噪的方法 提出的方法 2.1 Layer Decomposition Net 2.2 Reflectance Restoration Net 2.3 Illumination Adjustment Net 实验结果 总结 Kindling the Darkness: A Practical L…

在线课堂知识付费积分兑换小程序源码系统 带完整搭建教程

大家好啊&#xff0c;今天罗峰来给大家分享一个在线课堂知识付费积分兑换小程序源码系统&#xff0c;以下是部分功能实现核心代码图&#xff1a; 系统特色功能一览&#xff1a; 积分获取&#xff1a;用户可以通过在平台上的各种操作&#xff0c;例如观看直播课程、学习文章、完…

塑料透光率测试可测试塑料部件的透明度和纯度

随着电子设备的快速发展&#xff0c;尤其是智能手机、平板电脑、可穿戴设备等新兴产品的普及&#xff0c;对塑料材料的需求量也在逐渐增加。因为这些电子设备需要大量的塑料材料来制造外壳、内部结构、部件等。电子设备在塑料行业的发展迅速&#xff0c;推动了塑料材料的技术进…

苹果手机怎么恢复数据?推荐这款数据恢复软件!

苹果手机一直以高颜值、系统稳定&#xff0c;以及优质的用户体验而闻名&#xff0c;这也使得购买苹果手机的用户逐渐增多。在手机中我们会保存各种各样的数据&#xff0c;包括照片、视频、备忘录、聊天记录等等。但是&#xff0c;这些数据可能会因为某些原因而导致丢失。 那么…

如何转换Corona和Vray材质?cr材质转vr材质的方法

cr材质转vr材质的方法一&#xff1a;使用CG Magic插件&#xff0c;一键转换 CG Magic是一款基于3ds Max深度开发的智能化辅助插件&#xff0c;上千项实用功能&#xff0c;降低渲染时长&#xff0c;节省时间和精力&#xff0c;大幅简化工作流程&#xff0c;助力高效完成创作。 …

Day3力扣打卡

打卡记录 改变一个整数能得到的最大差值&#xff08;贪心&#xff09; 链接 得到最大的整数&#xff0c;找到一个高位将它修改为 9。同理&#xff0c;想要得到最小的整数&#xff0c;找到一个高位将它修改为 0。 class Solution { public:int maxDiff(int num) {auto replace …

5种常见的软件缺陷分析方法

软件缺陷分析方法对于软件开发非常重要&#xff0c;能够帮助团队识别和分析软件中的缺陷问题&#xff0c;从而制定相应的解决方案&#xff0c;并持续改进软件质量和可靠性。通过合理应用这些方法&#xff0c;可以大幅提高软件开发效率和质量。 软件开发过程中&#xff0c;可能存…

Mysql 内外链接,索引,事务,用户管理以及用C语言链接Mysql

文章目录 内外链接索引索引的相关操作全文索引 事务事务的操作事务的隔离级别隔离级别3个记录隐藏列字段 用户管理权限修改 使用C语言链接数据库 内外链接 两张表直接做笛卡尔积为内连接&#xff0c;之前使用的都是内连接 两张表&#xff1a;stu和exam 将两张表进行连接&…