vector的模拟实现

一、vector的基本结构

template<class T>
class vector
{
public:
	typedef T* iterator;
	typedef const T* const_iterator;
private:
	iterator _start;//vector的迭代器,指向起始位置
	iterator _finish;//指向存放最后一个元素的下一个位置
	iterator _end_of_storage;//指向容量的最后一个位置
};

         我们可以得知,_finish - _start就是顺序表vector的大小;_end_of_storage - _start 就是顺序表vector的容量。

二、vector的默认成员函数 

1、构造函数

这里实现了三个构造函数,一个是默认构造,一个是用n个值构造,一个用迭代器区间构造。 

//默认构造函数
vector()
	:_start(nullptr)
	,_finish(nullptr)
	,_end_of_storage(nullptr)
{}

//用n个value构造
vector(int n, const T& value = T())
{
	_start = new T[n];
	for (int i = 0; i < n; ++i)
	{
		_start[i] = value;
	}
	_finish = _start + n;
	_end_of_storage = _finish;
}

//用迭代器区间构造
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
	int n = last - first;
	_start = new T[n];
	int i = 0;
	while (first != last)
	{
		_start[i++] = *first;
		++first;
	}
	_finish = _start + n;
	_end_of_storage = _finish;
}

 2、析构函数

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

3、拷贝构造

a、这是较为简单的现代写法,用v构造一个tmp,然后把tmp的资源全部交换给自己,就完成了拷贝 ,不需要手动释放tmp,出了函数会自动调用析构函数处理。

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(const vector<T>& v)
{
	_start = _finish = _end_of_storage = nullptr;
	vector<T> tmp(v.cbegin(), v.cend());
	swap(tmp);
}

b、这是一般的写法 

vector(const vector<T>& v)
{
	int capacity = v.capacity();
	int sz = v.size();
	_start = new T[capacity];
	_finish = _start + sz;
	_end_of_storage = _start + capacity;
	for (int i = 0; i < sz; ++i)
	{
		*(_start + i) = v[i];
	}

}

 4、移动赋值

与拷贝构造类似,用v构造一个tmp,最后将tmp的资源交换给自己即可。因为函数结束后会调用析构函数释放tmp,会把原本的空间释放,所以不用手动释放空间了。

vector<T>& operator=(const vector<T>& v)
{
	vector<T> tmp(v.cbegin(), v.cend());
	swap(tmp);

	return *this;
}

三、迭代器有关接口

由上面的结构(一)可以看到vector的迭代器就是 T* 

typedef T* iterator;
typedef const T* const_iterator;

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

 四、其他的函数

1、大小size与容量capacity

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

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

 2、reserve

        如果n比 这个vector的容量大,就扩容到n,如果更小,就什么都不用干。

void reserve(size_t n)
{
	if (_start + n > _end_of_storage)
	{
		int sz = size();
		T* tmp = new T[n];
		//memcpy(tmp, _start, size() * sizeof(T));
		for (int i = 0; i < sz; ++i)
		{
			tmp[i] = _start[i];
		}
		delete[] _start;
		_start = tmp;
		_finish = _start + sz;
		_end_of_storage = _start + n;
	}
}

3、resize

        如果n小于size,就把size减为n;如果n大于size,就把大于size的部分用val赋值;如果n大于capacity,就扩容到n。 

void resize(size_t n, const T& value = T())
{
	if (_start + n > _finish)
	{
		int end = size();
		reserve(n);
		for (int i = end; i < n; ++i)
		{
			_start[i] = value;
		}
	}
	else
	{
		_finish = _start + n;
	}
}

五、增加、删除与方括号的重载

1、[]的重载

        []的重载可以让我们像数组一样用下标访问vector

T& operator[](size_t pos)
{
	return _start[pos];
}

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

2、尾插和尾删 

void push_back(const T& x)
{
	if (_finish == _end_of_storage)
	{
		int newcapacity = _finish == nullptr ? 4 : 2 * capacity();
		reserve(newcapacity);
	}
	*_finish = x;
	++_finish;
}

void pop_back()
{
	--_finish;
}

 3、任意位置的插入和删除

        任意删除位置就是从 pos+1 位置,后一个数不断覆盖前一个数,最后--_finish就完成了pos位置的删除。

        任意插入位置就是从最后一个数开始,每一个数都往后挪一位,到pos位置挪完后,再将值插入到pos位置。

iterator erase(iterator pos)
{
	assert(pos >= _start);
	assert(pos < _finish);
	//memmove(pos, pos + 1, (_finish - pos - 1) * sizeof(T));
	iterator begin = pos;
	while (begin < _finish - 1)
	{
		*begin = *(begin + 1);
		begin++;
	}
	--_finish;
	return pos;
}

iterator insert(iterator pos, const T& x)
{
    if (_finish == _end_of_storage)
    {
    	int posi = pos - _start;
        int newcapacity = _finish == nullptr ? 4 : 2 * capacity();
	    reserve(newcapacity);
    	pos = _start + posi;
    }

    //memmove(pos + 1, pos, (_finish - pos) * sizeof(T));
    iterator end = _finish - 1;//n-1
    while (end >= pos)
    {
	    *(end + 1) = *end;
    	end--;
    }
    *pos = x;
    ++_finish;
    return pos;
}

六、迭代器失效问题

        当我们插入或删除一个值时,有可能会导致扩容或缩容,而我们的迭代器还指向旧的空间,就会导致我们的迭代器失效。

void test3()
{
	lw::vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	
	lw::vector<int>::iterator it = v1.begin();
	while (it != v1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

我们上述代码就是简单的使用迭代器遍历vector,结果如下:

而我们执行如下代码时:假如我们想在2的前面插入一个20

void test3()
{
	lw::vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	
	lw::vector<int>::iterator it = v1.begin();
	while (it != v1.end())
	{
		cout << *it << " ";
		if (*it == 2)//假如我们想在2的前面插入一个20
		{
            v1.insert(it, 20);
            it++;
        }
		it++;
	}
	cout << endl;
}

执行结果就变为了:

 因为insert后,会扩容,数据已经存到新的空间,而我们使用的迭代器 it 依旧指向旧的空间,就会出现随机值。 

 

而使用erase时,因为底层实现不知道,有可能会缩容,所以也有可能会导致迭代器失效。

感谢大家观看! 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++类与对象(四):再谈构造函数(详解初始化列表)、Static成员

上次把默认的成员函数部分梳理完毕了&#xff1a;C初阶类与对象&#xff08;三&#xff09;&#xff1a;详解复制构造函数和运算符重载 今天接着讲下面的内容&#xff1a; 文章目录 1.再谈构造函数1.1构造函数体赋值1.2初始化列表1.2.1格式和概念1.2.2由来情况1情况2 1.2.3特性…

C语言第三弹---数据类型和变量

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 数据类型和变量 1、数据类型介绍1.1、整型1.2、浮点型1.3、字符型1.4、布尔类型1.5、各种数据类型的长度1.5.1、sizeof操作符1.5.2、数据类型的长度1.5.3、sizeo…

全网最详细!!Python 爬虫快速入门

1. 背景 最近在工作中有需要使用到爬虫的地方&#xff0c;需要根据 Gitlab Python 实现一套定时爬取数据的工具&#xff0c;所以借此机会&#xff0c;针对 Python 爬虫方面的知识进行了学习&#xff0c;也算 Python 爬虫入门了。 需要了解的知识点&#xff1a; Python 基础语…

【蓝桥杯EDA设计与开发】立创开源社区分享的关于蓝桥被EDA真题与仿真题的项目分析

立创开源社区内有几个项目分享了往年 EDA 设计题目与仿真题&#xff0c;对此展开了学习。 【本人非科班出身&#xff0c;以下对项目的学习仅在我的眼界范围内发表意见&#xff0c;如有错误&#xff0c;请指正。】 项目一 来源&#xff1a;第十四届蓝桥杯EDA赛模拟题一 - 嘉立…

JS-WebAPIs-其他事件(三)

• 页面加载事件 页面加载事件主要有二种事件&#xff0c;分别是load和DOMContentLoaded 加载外部资源&#xff08;如图片、外联CSS和JavaScript等&#xff09;加载完毕时触发的事件为什么要学&#xff1f; 有些时候需要等页面资源全部处理完了做一些事情老代码喜欢把 scrip…

Git教程学习:01 Git简介与安装

目录 1 版本控制1.1 什么是版本控制系统&#xff1f;1.2 本地版本控制系统1.3 集中式版本控制系统1.4 分布式版本控制系统 2 Git简史3 Git的安装3.1 在Linux上安装3.2 初次运行Git前的配置 1 版本控制 1.1 什么是版本控制系统&#xff1f; 版本控制系统(Version Control Syst…

LLaVA-Plus: Learning to Use Tools for Creating Multimodal Agents

LLaVA-Plus: Learning to Use Tools for Creating Multimodal Agents 最近在调研一些多模态大模型相关的论文&#xff0c;发现Arxiv上出的论文根本看不过来&#xff0c;遂决定开辟一个新坑《一页PPT说清一篇论文》。自己在读论文的过程中会用一页PPT梳理其脉络和重点信息&#…

【2023】java使用WebClient实现chatGPT调用建立web socket连接

&#x1f4bb;目录 一、介绍1、使用技术2、效果 二、代码1、前端代码2、后端代码2.1、maven依赖2.2、model2.2.1、请求接口的格式2.2.2、响应数据对象 2.3、工具类2.3.1、&#x1f534;使用WebClient调用chatgpt方法2.3.2、&#x1f7e0; webSocket连接对话方法 2.4、Controlle…

【微信小程序开发】环境介绍和基本使用

文章目录 前言1. 项目的基本组成结构1.1 JSON 配置文件的作用1.2 如何新建小程序页面1.3 修改项目首页1.4 WXML 模板1.5 WXSS 样式1.6 JS 逻辑交互 2. 宿主环境2.1 什么是宿主环境2.2 通信模型2.3 运行机制2.4 组件2.4.1 view 组件的基本使用&#xff1a;2.4.2 scroll-view 组件…

【数据结构与算法】1.时间复杂度和空间复杂度

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有限&#xff0c;欢迎各位大佬指点&…

vue3前端开发,生命周期函数的基础练习

vue3前端开发,生命周期函数的基础练习&#xff01; 下面先给大家看一个图片&#xff0c;帮助大家了解&#xff0c;vue3的生命周期函数&#xff0c;和旧版本vue2的生命周期函数&#xff0c;有什么变化。 如图所示&#xff0c;vue3里面&#xff0c;把前面2个函数&#xff0c;混在…

展锐T618_虎贲T618紫光展锐安卓核心板规格参数

基于紫光展锐八核T618平台的纯国产化方案&#xff0c;采用了开放的智能Android操作系统&#xff0c;并集成了4G网络、2.5G5G双频WIFI(可支持1*1 MIMO)、BLUETOOTH近距离无线传输技术以及GNSS无线定位技术。用户可以根据特定场合的需求&#xff0c;选择合适的嵌入式ARM核心模块&…

禅道的安装及使用

文章目录 1.禅道的下载安装2.禅道管理员管理账户3.禅道管理产品角色操作4.禅道关联需求 1.禅道的下载安装 1、禅道下载网址&#xff1a;http://www.zentao.net/ 2、下载好之后把该文件放到D盘上 3、双击点开然后点击”Extract“进行解压该文件 4、解压中 5、解压完就会出现…

Git学习笔记(第5章):Git团队协作机制

目录 5.1 团队内协作 5.2 跨团队协作 Git进行版本控制都是在本地库操作的。若想使用Git进行团队协作&#xff0c;就必须借助代码托管中心。 5.1 团队内协作 问题引入&#xff1a;成员1&#xff08;大佬&#xff09;利用Git在宿主机上初始化本地库&#xff0c;完成代码的整体…

Oracle 12CR2 RAC部署翻车,bug避坑经历

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

【原文链接】Tri-Perspective View for Vision-Based 3D Semantic Occupancy Prediction

原文链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2023/papers/Huang_Tri-Perspective_View_for_Vision-Based_3D_Semantic_Occupancy_Prediction_CVPR_2023_paper.pdf 1. 引言 体素表达需要较大的计算量和特别的技巧&#xff08;如稀疏卷积&#xff09;&…

Java(spring cloud)智慧工地(项目层+工地层+APP)源码

智慧工地提供工地智能管理服务&#xff0c;打通数据壁垒&#xff0c;互通管理中心各平台。实现&#xff1a;“可视”、“可控”、“可管”。智慧工地管理云平台是一种利用人工智能和物联网技术来监测和管理建筑工地的系统。它可以通过感知设备、数据处理和分析、智能控制等技术…

chatgpt国内使用网站(免费收藏级)

如果您认为本文对你有帮助&#xff0c;希望可以点赞收藏&#xff01;感谢您的支持 下面我为你推荐我自己在用的gpt类工具&#xff0c;帮你在工作学习生活上解决一些大小问题 &#x1f389;智能GPT 地址&#xff1a; https://meet.adminjs.net 在他的详情中有详细的使用介绍&am…

统信UOS_麒麟KYLINOS安装JDBC驱动包

原文链接&#xff1a;统信UOS/麒麟KYLINOS安装JDBC驱动包 亲爱的读者们&#xff0c;大家好&#xff01;今天&#xff0c;我为大家带来一篇非常实用的技术文章——在统信UOS和麒麟KYLINOS操作系统上&#xff0c;如何使用Dbeaver连接Oracle数据库。Dbeaver是一个广泛使用的数据库…

工业设备管理系统:助力企业实现数字化转型

随着工业4.0和智能制造的快速发展&#xff0c;数字化转型已成为企业提升竞争力、适应市场变化的必然选择。工业设备管理系统作为数字化转型的关键组成部分&#xff0c;能够为企业提供实时监控、数据分析、预警和远程控制等功能&#xff0c;助力企业实现数字化转型的目标。 一、…