STL中vector模拟实现

vector各个接口函数

//构造函数
vector()
vector(size_t n,const T& val=T())
vector(int n,const T& val = T())
//拷贝构造函数
vector(const vector<T>& v)
//迭代器版本的
vector(inputiterator first, inputiterator end)
//赋值运算符重载
vector<T>& operator=( vector<T> v)
//析构函数
~vector()
//容量相关的函数
void reserve(size_t n)//扩容版本
void resize(size_t n, T val = T())//扩容+初始化版本
size_t size()const//数量
size_t capacity() const容量
//插入修改容器中的数据的函数
void push_back(T x)
iterator insert(iterator pos, const T& val)
iterator erase(iterator pos)
迭代器相关的函数
iterator begin()//指向首元素
iterator end()//指向最后一个元素的下一个位置
const_iterator begin()const 
const_iterator end()const
//容器中数据访问的[]
T& operator[](size_t pos)
const T& operator[](size_t pos)const

vector成员中相关成员变量

vector本质上就是一个动态开辟的数组,里面的成员跟以前的顺序表没啥本质区别,但是vector是用模板实现的,可以任意类型的数据。我们也可以看看源码中vector是怎么实现的呢?
在这里插入图片描述

分别使用了一个迭代器的指针,一个表示首元素,一个表示最后一个元素的下一个位置,还有一个就是end_of_storage表示容量。我在下面的写的vector当中给了缺省值,避免每次写构造函数的时候都要初始化一下。

private:
iterator _start=nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;

默认成员函数

我给了缺省值,会自动走初始化列表,因此我在这边不要在初始化一下了。

vector()
{}

构造函数的实现
vector支持一种这样的构造,你可以给出n个你想初始化的值,在l类与对象那么我们知道构造函数对内置类型不做处理,对自定义类型会去调用它的构造函数。但是C++11以后对内置类型也会做处理了。int x= int(); char c=char();

vector(size_t n,const T& val=T())//c++11之后支持对内置类型也会初始化
{if (size() + n > capacity()){reserve(size() + n);}while ((int)n--)//会发生隐式类型的转化{push_back(val);}_finish += n;}

我上面还写了一个int类型的构造这边就不放了,主要是模板会自动匹配它的最优选择,我们一般给vector v(10,1);会自动隐式类型转换成int int 的类型。

拷贝构造函数

写法思路就是_start先开辟一块与该容器大小相等的空间,然后将该容器的数据一个一个的拷贝过来,最后改变一下_finish跟_end_of_storage

vector(const vector<T>& v)
{std::cout << "vector(const T& v)" << std::endl;_start = new T[v.capacity()];//memcpy(_start, v._start, v.size()*sizeof(T));for (size_t i = 0; i < v.size(); i++){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();
}

赋值运算符重载的函数

传统写法
思路就是开辟一个与容器大小相同的tmp空间,然后将容器中数据传给tmp数组,思路跟拷贝构造后面一致。

//传统写法
vector<T>& operator=(vector<T>& v)
{if (this != &v){iterator tmp = new T[v.capacity()];for (size_t i = 0; i < v.size(); i++){tmp[i] = v._start[i];}_start = tmp;_finish = _start + v.size();_end_of_storage = _start + v.capacity();}return *this;
}

现代写法

就是通过算法库里面的swap交换一下俩者的指针所指向的地址

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

迭代器版本的构造函数
vector还支持使用一段迭代器区间进行对象的构造。因为该迭代器区间可以是其他容器的迭代器区间,也就是说该函数接收到的迭代器的类型是不确定的,所以我们这里需要将该构造函数设计为一个函数模板,在函数体内将该迭代器区间的数据一个个尾插到容器当中即可。

template<class inputiterator>
//迭代器版本默认是左闭右开的
vector(inputiterator first, inputiterator end)
{while (first != end){push_back(*first);first++;}
}

析构函数

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

容量相关的函数

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

reserve的实现规则就是判断当前的是否达到最大的容积,达到就扩容,开辟一块tmp空间,当_start不为空的时候就开始挪动数据。

void reserve(size_t n)
{if (n > capacity()){iterator tmp = new T[n];//挪动数据if (_start){size_t sz = size();//memcpy(tmp, _start, sizeof(T) * sz);//浅拷贝for (size_t i = 0; i < size(); i++){tmp[i] = _start[i];//实现深拷贝}}delete[] _start;_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}
}

resize函数实现的思路就是当输入n小于当前内存的时候我们就不需要初始化,并且跟新一下_finish=_start+n,,当大于的时候就需要分俩种情况,一种是当vector为空的时候,我们就直接在头部开始插入数据,第二种就是本来就有数据,需要尾插数据一直达到n个大小。

void resize(size_t n, T val = T())
{if (n <=size()){_finish =_start+n;}else{reserve(n);while ((int)n--){if (_start){push_back(val);}else{insert(begin(), val);}}}
}

插入修改容器中的数据的函数

尾插数据push_back,实现思路就是插入数据首先就是扩容,然后在finish后面插入数据,然后让finish++一下。

void push_back(T x)
{if (_finish >= _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;_finish++;
}

insert()的写法,以前的写法就是给一个下标pos的位置,然后删除对应pos位置上的数据,而现在这个pos变成了指针,我们在使用指针插入对应数据的时候,特别容易出现迭代器失效的情况,也就是野指针的行为,为啥呢?因此我们在插入数据的时候需要扩容,我们是额外开了一个数组,然后就会将原数组释放掉,再让_start指向新开辟的数组,所以我们需要保存pos指针的位置。

iterator insert(iterator pos, const T& val)
{assert(pos <=_finish);size_t len = pos - _start;if (_finish >= _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}iterator end = _finish - 1;pos = _start + len;//跟新pos指针的位置while (end >= pos){*(end + 1) = *end;end--;}*pos = val;_finish++;return pos;
}

erase的实现,在Linux跟vs中对erase()底层实现都有区别,vs中只要删除了该数据,该位置的值就不可访问或者解引用修改查看,而inux环境下就宽松了很多,我们可以随意的访问或者修改,但是出错了也意味着不容易判断。

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

迭代器相关的函数和数据访问

这个很简单直接放代码

iterator begin()
{return _start;
}
iterator end()
{return _finish;
}
const_iterator begin()const 
{return _start;
}
const_iterator end()const
{return _finish;
}
T& operator[](size_t pos)
{assert(pos <= size());return _start[pos];
}
const T& operator[](size_t pos)const
{assert(pos <= size());return _start[pos];
}

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

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

相关文章

DML 数据操纵语言学习笔记

一、DML 核心概念体系 1.1 语言定位与边界 DML&#xff08;Data Manipulation Language&#xff09;作为 SQL 三大核心语言之一&#xff0c;专注于数据行级操作&#xff0c;区别于 DDL&#xff08;结构定义&#xff09;和 DCL&#xff08;权限控制&#xff09;。其核心指令包…

springboot的跨域是什么?遇到跨域问题如何解决?

在Spring Boot中&#xff0c;跨域是指当浏览器中的前端应用&#xff08;如运行在某个域名和端口下的前端页面&#xff09;请求后端接口时&#xff0c;如果后端接口所在的域名、端口或协议与前端应用不一致&#xff0c;浏览器会阻止这种跨域请求。这是由于浏览器的同源策略&…

啸叫抑制(AFS)从算法仿真到工程源码实现-第八节-系统搭建

一、概述 系统分为录音模块、数据处理模块、播音模块。录音模块和播音模块使用alsa库进行读写数据。各模块为独立进程处理&#xff0c;模块之间使用命名管道进行数据的传输。数据处理模块我们使用基于频域的自适应滤波去啸叫算法。 二、工程实现 2.1 系统流程图 2.2 录音模块…

HTML——什么是块级元素,什么是内联元素,有何区别

在 HTML 中&#xff0c;块级元素&#xff08;Block-level element&#xff09;和内联元素&#xff08;Inline element&#xff09;是两种不同类型元素&#xff0c;它们在页面布局和样式应用方面有不同的行为和特性。 块级元素&#xff08;Block-level element&#xff09; 块级…

01 设计模式和设计原则

类设计原则&#xff1a; 单一职责原则&#xff08;Single Responsibility Principle&#xff0c;SRP&#xff09;&#xff1a;实现类要职责单一开闭原则&#xff08;Open Close Principle&#xff0c;OCP&#xff09;&#xff1a;对扩展开放&#xff0c;对修改关闭里氏替换原则…

【踩坑日记】springboot 打包后实现类无法找到

试过了所有改什么目录 依赖 clean都以失败告终 最后将实现类的文件名从Impl改成impl宣布成功 记得使用idea自带的重构

项目-苍穹外卖(十五) WebSocket+语音播报功能实现(来订单+催单)

一、介绍 二、入门案例 配置类&#xff1a; package com.sky.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;/…

【Spring篇】Spring的生命周期

一、Bean 生命周期的核心阶段 1. 实例化&#xff08;Instantiation&#xff09; • 触发时机&#xff1a;容器启动时&#xff08;单例 Bean&#xff09;或请求时&#xff08;原型 Bean&#xff09;。 • 实现方式&#xff1a; 通过反射&#xff08;Class.newInstance() 或构造…

Redis、Memcached应用场景对比

环境 Redis官方网站&#xff1a; Redis - The Real-time Data Platform Redis社区版本下载地址&#xff1a;Install Redis | Docs Memcached官方网站&#xff1a;memcached - a distributed memory object caching system Memcached下载地址&#xff1a;memcached - a dis…

kettle插件-mysql8数据库插件

场景&#xff1a;群里有小伙伴反馈kettle 7.x版本不能自动连接mysql8&#xff0c;安排&#xff01;&#xff01;&#xff01; 1、将mysql8的驱动包mysql-connector-java-8.0.20.jar丢到kettle的lib目录下&#xff0c;重启spoon。 2、配置数据库连接&#xff0c;提示驱动类不对…

【软件测试】:软件测试实战

1. ⾃动化实施步骤 1.1 编写web测试⽤例 1.2 ⾃动化测试脚本开发 common public class AutotestUtils {public static EdgeDriver driver;// 创建驱动对象public static EdgeDriver createDriver(){// 驱动对象已经创建好了 / 没有创建if( driver null){driver new EdgeDr…

深度学习入门1 基于Python的理论与实现

torch.unsqueeze()将一维数据变为二维数据&#xff0c;torch只能处理二维数据 tensor不能反向&#xff0c;variable可以反向。variable.data.numpy()转换为numpy 第3章 神经网络 实现softmax函数时的注意事项&#xff1a;为防止e的指数运算造成溢出 矩阵的第 0 维是列方向,第…

解决 Pentaho Kettle 插件集成中的 NoSuchMethodError: ContextFactory.enterContext() 错误

解决 Pentaho Kettle 插件集成中的 NoSuchMethodError: ContextFactory.enterContext() 错误 在使用 Pentaho Data Integration&#xff08;也称为 Kettle&#xff09;进行数据集成和ETL开发时&#xff0c;开发者可能会遇到各种依赖冲突和技术挑战。本文将详细介绍一个常见的错…

第 五 章:优化算法_《C++性能优化指南》_notes

优化算法 第五章重难点详解与代码实战编译与测试说明第五章核心知识点整理重难点梳理 第一部分&#xff1a;多选题&#xff08;10道&#xff09;第二部分&#xff1a;设计题&#xff08;5道&#xff09;答案与详解多选题答案&#xff1a; 设计题参考实现&#xff08;以题目2为例…

多版本PHP开发环境配置教程:WAMPServer下MySQL/Apache/MariaDB版本安装与切换

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、版本切换指南总结 前言 由于有几个项目分别使用到PHP7.0 和7.4以及8.0版本&#xff0c;设置mysql也会根据PHP版本使用不同的版本&#xff0c;于是开始研究…

2024年数维杯数学建模C题天然气水合物资源量评价解题全过程论文及程序

2024年数维杯数学建模 C题 天然气水合物资源量评价 原题再现&#xff1a; 天然气水合物&#xff08;Natural Gas Hydrate/Gas Hydrate&#xff09;即可燃冰&#xff0c;是天然气与水在高压低温条件下形成的类冰状结晶物质&#xff0c;因其外观像冰&#xff0c;遇火即燃&#…

阶段一:Java基础语法

目标&#xff1a;掌握Java的基本语法&#xff0c;理解变量、数据类型、运算符、控制结构等。 1. Java开发环境搭建 安装JDK配置环境变量编写第一个Java程序 代码示例&#xff1a; // HelloWorld.java public class HelloWorld { // 定义类名为 HelloWorldpublic static vo…

从0到1,解锁Ant Design X的无限可能

Ant Design X 是什么&#xff1f; 在人工智能飞速发展的当下&#xff0c;AI 驱动的界面已成为软件开发的重要趋势。而 Ant Design X 正是顺应这一趋势&#xff0c;于 2024 年应运而生的一款遵循 Ant Design 设计体系的 React UI 库&#xff0c;它旨在帮助开发者轻松打造 AI 驱…

Graphpad Prism for Mac医学绘图

Graphpad Prism for Mac医学绘图 文章目录 Graphpad Prism for Mac医学绘图一、介绍二、效果三、下载 一、介绍 GraphPad Prism for Mac是一款功能强大、易于使用的科学和统计分析软件&#xff0c;适用于各种类型的数据处理和可视化需求。无论您是进行基础研究、临床试验还是学…

mysqloracledb2 (uuid函数)

项目场景&#xff1a; 创建一个32位的UUID 问题描述 原因分析&#xff1a; 解决方案&#xff1a; mysql内置UUID函数 SELECT UUID(); SELECT UUID_SHORT();oracle内置UUID函数 SELECT sys_guid() FROM dual;db2&#xff0c;模拟UUID函数 SELECT TEST || substr (CONCAT…