【C++】vector类:模拟实现(适合新手手撕vector)

在实现本文的vector模拟前,建议先了解关于vector的必要知识:【C++】容器vector常用接口详解-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/2301_80555259/article/details/141529230?spm=1001.2014.3001.5501


目录

一.基本结构

二.构造函数(constructor)

三.迭代器(iterator)

四.容量操作(capacity)

1.resize

2.reserve

五. 修改操作(modify)

六.访问操作(access)

七.重载赋值运算符

八.析构函数(destructor)

九.打印(print)


一.基本结构

创建头文件:vector.h 实现文件:vector.cpp 测试文件:test.cpp

当然此处为了简化直接使用了头文件+测试文件,在自定义的命名空间内创建vector类,配上基本结构:

由于vector是顺序表,因此和C语言实现顺序表时一样,至上有三个参数:

  1. 指向一段连续空间的指针
  2. 空间的有效大小
  3. 空间的实际大小

实现vector的迭代器,可以就将其视为指针,因此可以使用三个迭代器(指针)就完成上述三个参数的实现,它们分别是_start,_finish,_end_of_storage,此时

  1. 指向一段连续空间的指针:_start
  2. 空间的有效大小size:_finish - _start
  3. 空间的实际大小capacity:_end_of_storage - _start

template<class T>
class vector
{
public://用指针实现vector的迭代器typedef T* iterator;typedef const T* const_iterator;
private:iterator _start;iterator _finish;iterator _end_of_storage;
};

二.构造函数(constructor)

//无参构造
vector():_start(nullptr),_finish(nullptr),_end_of_storage(nullptr)
{}
//带参构造,用n个value来初始化vector
vector(int n, const T& value = T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{reserve(n);for (int i = 0; i < n; i++){push_back(value);}
}
//拷贝构造
vector(const vector& v):_start(nullptr),_finish(nullptr),_end_of_storage(nullptr)
{//易错点:这里并没有进行初始化reserve(v.size());for (auto e : v){push_back(e);}
}//迭代器区间构造
template<class InputIterator>
vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{while (first != last){push_back(*first);first++;}
}

这里单独把这个构造拿出来谈谈, 最开始我只在无参构造中使用初始化列表,没有对其他构造函数的_start等进行初始化,这个bug我找了半天,每一个构造也是构造函数,跟其他构造函数没有关系,是凭借拷贝构造自身创建一个新的对象,因此也要进行初始化序列来初始化。这是最为保险的,否则就要在成员变量声明处加上默认值。

发现这个错误的bug就在使用赋值重载时,临时变量需要调用拷贝构造,但若此时拷贝构造没有去手动写初始化列表,那么其_finish和_end_of_storage不是nullptr,是随机值,这样就导致了错误

然而在有参构造时,尽管没去写初始化列表,对应的_start和_finish等也都是nullptr,此时就没有问题,但是为了保险,我建议所有构造函数都应该去手写一遍初始化列表。

三.迭代器(iterator)

iterator begin()
{return _start;
}
iterator end()
{return _finish;
}
const_iterator begin()const
{return _start;
}
const_iterator end()const
{return _finish;
}

四.容量操作(capacity)

容量操作方面的函数有:

  • size
  • capacity
  • empty
  • resize
  • reserve

前三个较为简单,很容易实现:

size_t size()const
{return _finish - _start;
}
size_t capacity()const
{return _end_of_storage - _start;
}
bool empty()const
{return size() == 0;
}

1.resize

resize会改变size的大小,同时也有可能改变capacity的大小,具体要分三种情况:

  1. n大于capacity时:直接套用reserve扩容后再初始化新内容
  2. n大于size小于capacity时:有效值不变的情况下初始化新内容
  3. n小于size时:直接将size缩小到n
void resize(size_t n, const T& value = T()) 
{if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish != _start + n){*_finish = value;_finish++;}}
}

如何来理解:const T& value = T() ?
 

在C++中内置类型(如int,double,char)特殊处理过,升级为了类,也有默认构造函数,它会将变量初始化为默认值。

此处使用了匿名对象

int tmp1 = int();//0
int tmp2 = int(10);//10

2.reserve

reserve扩容也是同理,只在n大于capacity的时候进行扩容

void reserve(size_t n)
{if (n > capacity()){//记录原本的数据个数size_t old_size = size();iterator tmp = new T[n];memcpy(tmp, _start, old_size * sizeof(T));delete[] _start;_start = tmp;_finish = tmp + old_size;_end_of_storage = tmp + n;}
}

五. 修改操作(modify)

//modify
void push_back(const T& x)
{if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = x;_finish++;
}
void pop_back()
{assert(size() > 0);--_finish;
}
iterator insert(iterator pos, const T& x)
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){//注意这里扩容会使原有的pos迭代器失效//因此这里使用len计算相对长度,更新迭代器size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;}iterator end = _finish;while (end > pos){*end = *(end - 1);end--;}*pos = x;++_finish;return pos;
}
void erase(iterator pos)
{assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;it++;}--_finish;
}

六.访问操作(access)

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

七.重载赋值运算符

注意这里的参数不是常量引用,而是按值传递。这是因为之后调用swap函数,按值传递可以使得传入的参数会被复制一份给临时对象,从而避免了对原对象的修改。

//operator =
void swap(vector& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);
}//在模板内,写vector和vector<T>都行
//因为要交换内部内容,因此不加const 
vector& operator=(vector v)
{swap(v);return *this;
}

八.析构函数(destructor)

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

九.打印(print)

template<class T>
void print_vector(const vector<T>& v)
{//规定,从没有实例化的类模版中取东西//编译器不能区分const_iterator是类型还是静态成员变量,因此要加typename//当然也可以更简单写为auto it  = v.begin();typename vector<T>::const_iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;
}template<class container>
void print_container(const container& v)
{for (auto e : v){cout << e << " ";}cout << endl;
}

本文结束,下次将会介绍容器中的list,和vector是类似的,但也有不同,欢迎持续关注

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

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

相关文章

elementUI根据列表id进行列合并@莫成尘

本文章提供了elementUI根据列表id进行列合并的demo&#xff0c;效果如图&#xff08;可直接复制代码粘贴&#xff09; <template><div id"app"><el-table border :data"tableList" style"width: 100%" :span-method"objectS…

C++从入门到起飞之——list使用 全方位剖析!

​ &#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 目录 1、迭代器 2、push_back与emplace_back 3、list成员函数sort与库sort比较 4、merge 5、uniqu…

讨论运维监控工具的普及程度

在讨论运维监控工具的普及程度时&#xff0c;加入PIGOSS BSM产品的分析是非常有意义的&#xff0c;因为PIGOSS BSM是一款在中国市场具有一定影响力的运维监控工具。 PIGOSS BSM运维监控工具是一款综合性的IT运维监控解决方案&#xff0c;它能够对多层次的IT资源进行监测&#x…

MQTT Client源码分析

MQTT Client源码分析 目录 MQTT Client源码分析1. mqttclient架构1.1 API1.2 mqtt_client_t结构体1.3 mqtt_yield_thread内部线程1.4 keepalive1.5 ack链表 2. mqttclient流程2.1 MQTT CONNECT2.2 MQTT SUBSCRIBE2.3 MQTT PUBLISH2.4 接收服务器PUBLISH消息 之前基于杰杰的mqtt…

大数据-118 - Flink DataSet 基本介绍 核心特性 创建、转换、输出等

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

手机怎么把wmv转换成mp4格式?视频格式这样做,让你的视频更加通用

“我最近想在手机上编辑视频&#xff0c;但遇到一个问题&#xff0c;就是我有一些wmv格式的视频&#xff0c;想把它们转换成mp4格式&#xff0c;好把它们发布到平台上。但是我不会转格式。请问手机怎么把wmv转换成mp4格式呢&#xff1f;请大家帮帮我。” 格式转换对于没怎么接…

JAVA 二维码生成

1.pom依赖 <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.3</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>ja…

四川财谷通抖音小店创新引领新风尚

在数字化浪潮的推动下&#xff0c;电商行业蓬勃发展&#xff0c;抖音小店作为新兴的电商平台&#xff0c;凭借其独特的社交属性和便捷的购物体验&#xff0c;迅速赢得了广大消费者的青睐。在众多抖音小店中&#xff0c;四川财谷通抖音小店以其精准定位、高质量内容、一站式服务…

智慧公厕:城市公共卫生管理的新篇章‌@卓振思众

在快节奏的现代生活中&#xff0c;公共厕所作为城市基础设施的重要组成部分&#xff0c;其使用体验和管理效率直接影响着市民的生活质量与城市形象。随着科技的飞速发展&#xff0c;智慧公厕应运而生&#xff0c;它以一种全新的姿态&#xff0c;为城市公共卫生管理带来了前所未…

鸿蒙Harmony--状态变量更改通知--@Watch装饰器详解

风雨飘摇中&#xff0c;我心起伏&#xff0c; 万丈雄心&#xff0c;却难以施展。 天高地远&#xff0c;路途迷茫&#xff0c; 理想如星&#xff0c;却遥不可及。 千百次跌倒&#xff0c;千百次爬起&#xff0c; 在命运的手掌中&#xff0c;挣扎前行。 谁知我心中的热血滚烫&…

向 ADC 模型和 DAC 建模添加低通滤波器

与单音测试信号相比&#xff0c;双音测试信号可提供更多有关 ADC 性能的信息。您的作者的模型与特定 ADC 的制造商模型非常匹配&#xff0c;因此可以方便地运行误码率模拟。该 ADC 恰好具有非常宽的输入带宽。 对于带宽较低的 ADC&#xff0c;添加如图 1 所示的低通滤波器将提…

用亚马逊AI代码开发助手Amazon Q Developer开发小游戏(中篇)

快用人工智能帮程序员写代码、开发游戏&#xff01;今天小李哥就来介绍亚马逊推出的国际前沿人工智能AI代码开发助手Amazon Q Developer。目前该代码助手在Hugging Face代码生成权威测试集SWE-bench中排名第一&#xff0c;可以根据我们的需求生成整个代码项目&#xff0c;并可以…

IDEA莫名奇妙自动选择光标所在行 -罪魁祸首居然是钉钉

请看受害者视角 作为开发者&#xff0c;工作时基本都会运行钉钉吧。最近&#xff0c;钉钉更新了AI功能&#xff0c;但不知道是不是开发团队平时不使用IDE&#xff0c;竟然让这个AI功能影响到了其他软件&#xff0c;简直让人无语。不仅仅是IDEA受影响&#xff0c;就连WebStorm也…

QQ聊天记录删除了怎么恢复?学会这3个方法,简单又有效

QQ作为我们日常沟通的重要工具之一&#xff0c;其聊天记录往往承载着许多珍贵的记忆和重要的信息。但在操作中我们会不小心删除或丢失这些聊天记录&#xff0c;那么QQ聊天记录删除了怎么恢复就成为我们急切需要解决的问题。先别急&#xff0c;本文就为你介绍3种简单又有效的QQ聊…

【Qt笔记】QListWidget控件详解

目录 引言 一、基本概念和特性 二、基本用法 2.1 创建和初始化 2.2 添加和删除项 2.3 选择和遍历项 三、信号与槽 3.1 itemClicked 3.2 itemDoubleClicked 3.3 itemSelectionChanged 四、自定义项 五、排序和查找 六、代码示例 6.1 头文件 6.2 源文件 6.3 主…

腾讯云TRTC无UI集成——分享屏幕主流、辅流(Vue2+JS+TRTC无UI集成)

先阐述一下问题&#xff0c;在项目中用到腾讯云的TRTC&#xff0c;A端发布A1、A2两个视频源&#xff0c;在B端订阅A1、A2使用两个view进行播放渲染 问题主流视频源和辅流视频源渲染在同一view上&#xff0c;控制台报错 // 播放远端视频 TRTCService.js; setRemoteVideo(view)…

【数据结构入门】排序算法之插入排序与选择排序

目录 前言 一、排序的概念及运用 1.排序的概念 2.排序的运用 3.常见排序算法 二、插入排序与选择排序 2.1插入排序 2.1.1直接插入排序 1&#xff09;基本思想 2&#xff09;具体步骤 3&#xff09;算法特性 4&#xff09;算法实现 2.1.2希尔排序 1) 基本思想 2&…

草原灭火车的功能与性能_鼎跃安全

在内蒙古的草原火灾中&#xff0c;水陆两栖全地形草原灭火车曾多次用于紧急救援。其强大的越野能力和高速反应&#xff0c;使其在广袤的草原上能够迅速到达火场&#xff0c;并使用集成的多功能灭火设备进行灭火作业&#xff0c;有效防止了火灾的进一步蔓延。 水陆两栖全地形草原…

React学习-hooks

官方文档&#xff1a;https://zh-hans.react.dev/reference/react/useActionState 1.useEffect(setup, dependencies?) 1.1 基础使用 //hooks import { useEffect } from "react"; import "./App.css";function App(){useEffect(()>{console.log(us…

redis的共享session应用

项目背景&#xff1a; 该项目背景就是黑马的黑马点评项目。 一&#xff1a;基于Session实现验证码登录流程 基本的登录流程我们做了很多了。这个是短信登录流程 其实和普通的登录流程就多了一个生成验证码&#xff0c;并将验证码保存在session中&#xff0c;并且呢&#xf…