【C++】vector(下)--上篇

news2024/9/23 7:20:53

在这里插入图片描述
个人主页~

vector(上)~


vector

  • 二、vector的模拟实现
    • 1、了解组成
    • 2、vector.h
      • (1)为什么有了size_t参数的vector构造函数还要再写一个int参数的重载vector构造函数
      • (2)为什么reserve不用memcpy
      • (3)reserve和resize的相关解释
      • (4)迭代器失效问题详解

二、vector的模拟实现

1、了解组成

首先我们需要在头文件stl_vector.h中了解vector的构成,它的三个私有成员分别是迭代器start、迭代器finish、迭代器endofstorage,分别指向vector的头、size的尾、capacity的尾

既然要实现了,自然要按照人家的标准最好,所以我们选择它们三个为私有成员变量

在这里插入图片描述

看一下vector的接口有哪些,当然我们还是去实现最基本也是重要最常用的那部分

在这里插入图片描述

2、vector.h

#pragma once

#include <iostream>
#include <assert.h>

namespace little_monster
{
	template <class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;

		//迭代器
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator begin() const
		{
			return _start;
		}
		const_iterator end() const
		{
			return _finish;
		}

		//构造、拷贝、析构函数
		vector()
		{}
		vector(size_t n, const T& value = T())
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				push_back(value);
			}
		}
		vector(int n, const T& value = T())
		{
			reserve(n);
			for (int i = 0; i < n; i++)
			{
				push_back(value);
			}
		}//(1)为什么有了size_t参数的vector还要再写一个int参数的
		template <class InputIterator>
		vector(InputIterator first, InputIterator end)
		{
			while (first != end)
			{
				push_back(*first);
				++first;
			}
		}
		vector(const vector<T>& v)
		{
			reserve(v.capacity());
			for (auto& e : v)
			{
				push_back(e);
			}
		}
		
		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}
		~vector()
		{
			delete[] _start;
			_start = _finish = _endofstorage = nullptr;
		}

		//容量
		size_t size() const
		{
			return _finish - _start;
		}
		size_t capacity() const
		{
			return _endofstorage - _start;
		}
		bool empty() const
		{
			if (_start == _finish)
			{
				return 1;
			}
			return 0;
		}
		void reserve(size_t n)
		{
			if (n > capacity())
			{
				T* tmp = new T[n];
				size_t sz = size();

				if (_start)
				{
					for (size_t i = 0; i < sz; i++)
					{
						tmp[i] = _start[i];
					}

					delete[] _start;
				}

				_start = tmp;
				_finish = _start + sz;
				_endofstorage = _start + n;
			}

		}//(2)为什么reserve不用memcpy
		void resize(size_t n, const T& val = T())
		{
			if (n > size())
			{
				reserve(n);
				while (_finish < _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
			else
			{
				_finish = _start + n;
			}
		}//(3)reserve和resize的相关解释

		//增删查改
		void push_back(const T& x)
		{
			if (_finish == _endofstorage)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}
			*_finish = x;
			++_finish;
		}
		void pop_back()
		{
			assert(_start < _finish);
			--_finish;
		}

		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);
			if (_finish == _endofstorage)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
			return pos;
		}
		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);
			iterator it = pos + 1;
			while (it < _finish)
			{
				*(it - 1) = *it;
				++it;
			}
			--_finish;
			return pos;
		}
		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		}
		T& operator[](size_t pos)
		{
			assert(pos < size());
			return _start[pos];
		}
		const T& operator[](size_t pos) const
		{
			assert(pos < size());
			return _start[pos];
		}	
	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _endofstorage = nullptr;
	};
}

有关模拟实现的几个问题,在下面一一解释

(1)为什么有了size_t参数的vector构造函数还要再写一个int参数的重载vector构造函数

在两个构造函数都存在的情况下程序正常运行

void test()
{
	vector<int> v(10,0);

	for (auto e : v)
	{
		std::cout << e << " ";
	}
	std::cout << std::endl;

}

在这里插入图片描述
屏蔽掉int参数的构造函数后,发生报错
在这里插入图片描述

这里的原因其实是下面的这个函数

template <class InputIterator>
vector(InputIterator first, InputIterator end)
{
	while (first != end)
	{
		push_back(*first);
		++first;
	}
}

这里的template < class InputIterator >用来声明一个类模版,它将接受一个迭代器类型的参数

我们看参数为10和0,在size_t参数构造函数中,两参数的类型为size_t和一个模版,而在该函数中为两个迭代器,也就是两个指针,在size_t参数构造函数中int需要强制类型转换为size_t,而该函数不用,两相比较下,软件会选择更合适的,但end一定要比begin大的,所以这里报错了,重载一个int类型的构造函数就能解决这个问题

(2)为什么reserve不用memcpy

reserve使用memcpy就会发生浅拷贝的问题,当删除旧空间的时候会发现我们reserve出来的空间不能使用了,因为memcpy将指针给拷贝过去,新的指针还是指向旧的空间,当旧的空间释放了就会出现野指针的错误(前面其他文章也有多次提到过深浅拷贝的问题了)

(3)reserve和resize的相关解释

关于reserve,它的参数有两种情况,第一种是参数n>capacity(),第二种就是n<=capacity()
在第二种情况下相当于是无事发生,第一种情况需要开辟新的空间之后,将数据转移到新空间,然后释放旧空间

关于resize,它的第一个参数有两种情况,第一种是参数n>size(),第二种是n<=size()
第一种情况下,会将size()和capacity()的大小都改变,将从原本的_finish位置开始一直到_endofstorage的前一个位置都初始化为第二个参数,第二种情况下直接将_finish提前就可以了

(4)迭代器失效问题详解

迭代器失效的问题在前面的文章当中提到过,这里搭配着insert和erase函数详细分析一下

迭代器失效问题跟上面第三个问题在根本是一样的,在reserve时,需要扩容,开辟新的空间之后,将数据转移到新空间,然后释放旧空间,那么这个指针就不能用了,因为其指向的空间已经释放了,当然resize也一样,所以我们要用深拷贝,new一个新空间然后数据转移释放旧空间


今日分享完毕~

在这里插入图片描述

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

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

相关文章

Mysql剖析(三)----MySql的事务详解

事务&#xff08;Transaction&#xff09;&#xff1a;一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中的各种数据项的一个程序执行单元&#xff08;unit&#xff09;。事务通常由高级数据库操纵语言或编程语言(如SQL、C或Java)书写的用户程序的执行所引…

Python脚本实现向飞书发送卡片消息

目录 1 先创建一个卡片消息2 Python脚本2.1 告警测试2.2 告警恢复 总结 1 先创建一个卡片消息 飞书卡片搭建工具 根据自己的需要创建一个消息卡片&#xff1a; 可以在 卡片源代码 中看到这个卡片的代码信息 2 Python脚本 2.1 告警测试 test.py 文件 ""&quo…

MacOS安装Docker Desktop

目录 安装Docker Desktop 1.下载 2.安装 3.验证 安装Docker Desktop 1.下载 访问Docker官方网站下载页面&#xff1a;https://www.docker.com/products/docker-desktop 选择自己所需的版本下载即可 2.安装 3.验证 1.查询版本号 docker --version 2.也可以运行一个简单的…

【vue、Electron】搭建一个Electron vue项目过程、将前端页面打包成exe 桌面应用

文章目录 前言使用 electron-vue 创建项目1. 安装 vue-cli&#xff08;如果未安装&#xff09;2. 使用 electron-vue 模板创建项目3. 安装和配置 electron-builder4. 运行Electron项目5. 打包应用 可能遇到的问题解决Electron vue首次启动巨慢无法加载执行npm run electron:bui…

从地图信息实时检测路口的各向通行状况、红绿灯及溢出情况

高德地图、百度地图都能获得实时的道路信息。 C# 编写的路况信息爬虫可获得准实时&#xff08;1分钟间隔&#xff09;的路口的各向通行状况、红绿灯及溢出情况。 优势&#xff1a; 投入少&#xff0c;效果好&#xff0c;无需安装设备&#xff1b; 缺陷&#xff1a; 时间间隔…

数据集不够用?3DGS助力生成带标注的全新扩展数据!

作者主页&#xff1a;https://louiszengcn.github.io/ 论文标题&#xff1a; Realistic Surgical Image Dataset Generation Based On 3D Gaussian Splatting 导读&#xff1a; 近年来&#xff0c;随着AI技术的飞速发展&#xff0c;数据量的增加为数据驱动的神经网络提供了更强…

汽车免拆诊断案例 | 2012 款大众速腾车发动机偶尔抖动

故障现象 一辆2012款大众速腾车&#xff0c;搭载CST发动机和干式双离合变速器&#xff0c;累计行驶里程约为17万km。车主反映&#xff0c;发动机偶尔抖动。 故障诊断 接车后试车&#xff0c;确认发动机怠速偶尔抖动&#xff0c;且在D挡起步时抖动明显。用故障检测仪检测&…

专题◉万字长文!盘点过去一年最出圈的Prompt项目教程,有3份在悄悄更新

1. OpenAI 官方出品 | 提示工程最权威的教程 (最新版) 2023年6月&#xff0c;OpenAI 发布了一篇〖*GPT Best Practice (GPT 最佳实践)* 〗教程&#xff0c;详细介绍 ChatGPT Prompt 交互策略&技巧&#xff0c;并且给出了示例说明。 一年时间过去了&#xff0c;OpenAI 不…

Unity射击游戏开发教程:(33)控制飞机左右移动

在本文中,我将介绍如何在玩家朝该方向移动时添加向左和向右转动的动画。 我们已经将左转和右转动画导入到我们的项目中。在我使用的动画中,它们只有两帧,因为我们希望飞机倾斜得很快,这样玩家在按下相应按钮时就能直接感觉到转弯。 </

为什么帕金森病患者在紧张或焦虑状态下震颤会加重?

为什么帕金森病患者在紧张或焦虑状态下震颤会加重&#xff1f; 帕金森病患者在紧张或焦虑状态下震颤加重的原因可能与多个因素有关。首先&#xff0c;帕金森病与大脑中多巴胺水平的降低有关&#xff0c;这种神经递质的失衡会影响运动控制。当患者感到紧张时&#xff0c;大脑皮…

嵌入式软件开发之状态机与事件驱动分析

状态机是一种程序架构,事件驱动也是一种程序架构,在某些开发场景里面,两者是可以一同合并使用的。 事件驱动的概念 生活中有很多事件驱动的例子,上自习瞒着老师偷睡觉就是很生动的一个。 我们都是从高中时代走过来的,高中的学生苦啊,觉得睡觉是世界上最奢侈的东西, 有时…

运维监控工具 PIGOSS BSM :PostgreSQL数据库监控指标

在PostgreSQL数据库中&#xff0c;为了确保其稳定运行和性能优化&#xff0c;我们需要监控一系列关键的指标。以下是一些主要的PostgreSQL监控指标介绍&#xff1a; 连接数&#xff08;Connections&#xff09;&#xff1a; 定义&#xff1a;连接数是指当前正在与数据库建立连…

数据库管理-第236期 数据库一体机的价值(20240829)

数据库管理236期 2024-08-29 数据库管理-第236期 数据库一体机的价值&#xff08;20240829&#xff09;1 误区2 硬件3 操作系统4 数据库总结 数据库管理-第236期 数据库一体机的价值&#xff08;20240829&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#xff08;尹海文&#xff…

深入探索【Hadoop】生态系统:Hive、Pig、HBase及更多关键组件(上)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《大数据前沿&#xff1a;技术与应用并进》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Hadoop简介 2、Hadoop生态系统的构成概览 3、…

native 添加堆栈

第一种方法 montecarloh53b getVehicleModel:default error: frameworks/native/services/surfaceflinger/Android.bp:248:1: module "surfaceflinger" variant "android_arm64_armv8-a": depends on //system/unwinding/libbacktrace:libbacktrace which …

YarnClient发送和接收请求源码解析

YarnClient发送和接收请求流程 Yarn是通过RPC协议通信的&#xff0c;协议类型可以通过查看RpcKind类得知&#xff0c;总共有三种类型&#xff1a; RPC_BUILTIN ((short) 1), // Used for built in calls by tests RPC_WRITABLE ((short) 2), // Use WritableRp…

CentOS 7安装和配置 NFS

前言 NFS 是 Network File System 的缩写&#xff0c;即网络文件系统。功能是让客户端通过网络访问不同主机上磁盘里的数据&#xff0c;主要用在类 Unix 系统上实现文件共享的一种方法。本例演示 CentOS 7 下安装和配置 NFS 的基本步骤。 环境说明 CentOS 7&#xff08;Mini…

Agent Q介绍:具有规划和自愈能力的下一代人工智能代理的研究突破

近年来&#xff0c;大型语言模型&#xff08;LLM&#xff09;的功能已经改变了自然语言处理和理解&#xff0c;取得了令人瞩目的里程碑式成就。尽管取得了这些进步&#xff0c;大型语言模型在交互环境中仍面临巨大挑战&#xff0c;尤其是在需要多步骤推理的任务中&#xff0c;如…

变电站智能巡检机器人:构建智能化电力运维新模式

随着现代电力系统规模的不断扩大&#xff0c;变电站作为电力输送和分配的关键节点&#xff0c;面临着越来越高的运维要求。传统的人工巡检方式存在效率低、劳动强度大、安全隐患多等问题&#xff0c;无法满足日益复杂的电力系统需求。在此背景下&#xff0c;变电站智能巡检机器…

偷偷用了这10款AI写作神器,再也没加过班!

前言 [ 自2022年Chat-GPT在全球掀起AI革命浪潮&#xff0c;AI开始在内容的生产方式进行颠覆性改变。 其中&#xff0c;AI写作工具的崛起&#xff0c;为内容创作者打开了一个全新创作世界&#xff0c;无论用户在办公写作、自媒体写作还是兴趣写作&#xff0c;在效率方面都得到…