首页 > 编程语言 >【C++】vector(下)--上篇

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

时间:2024-08-30 08:56:03浏览次数:7  
标签:finish const -- pos start vector 上篇 size

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

vector(上)~


vector

二、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一个新空间然后数据转移释放旧空间


今日分享完毕~

在这里插入图片描述

标签:finish,const,--,pos,start,vector,上篇,size
From: https://blog.csdn.net/s_little_monster/article/details/141534588

相关文章

  • openGauss-反向全量迁移
    openGauss-反向全量迁移特性简介本特性自openGauss5.1.0版本开始引入,支持openGauss的全量数据迁移至MySQL。客户价值反向迁移可满足用户业务迁移逃生的诉求。实现openGauss数据库全量数据迁移至MySQL数据库,可最大程度保持兼容性。特性描述debeziumopengaussconnector的s......
  • 线性代数 第三讲 线性相关无关 线性表示
    线性代数第三讲线性相关无关线性表示文章目录线性代数第三讲线性相关无关线性表示1.向量运算1.线性相关与线性无关1.1线性相关与线性无关基本概念2.线性表示(线性组合)3.线性相关无关与线性表示的定理大总结3.1向量β可由向量组线性表出的同义翻译3.2向量组线性......
  • C# WPF 如何使用折线图方案
    使用WPF的时候经常会出现需要使用折线图、柱状图的情况,一下为折线图的使用方案一、导入NuGet包项目搜索导入LiveCharts.Wpf包二、后端配置折线图需要调用 LineSeries、柱状图调用LineSeries、具体使用图形可参考官方网站 官方网址: LiveCharts这里举例说明折线图的......
  • openGauss-大页内存
    openGauss-大页内存可获得性本特性自openGauss5.1.0版本开始引入。特性简介通过操作系统大页内存的使用,优化数据库的共享内存,提升在大内存环境下数据库的性能表现。客户价值提升客户在大内存生产环境下数据库的性能表现。特性描述操作系统页表所需空间会随着运行环境总......
  • openGauss-动态数据脱敏机制
    openGauss-动态数据脱敏机制可获得性本特性自openGauss1.1.0版本开始引入。特性简介数据脱敏是行之有效的数据库隐私保护方案之一,可以在一定程度上限制非授权用户对隐私数据的窥探。动态数据脱敏机制是一种通过定制化制定脱敏策略从而实现对隐私数据保护的一种技术,可以有效......
  • 【机器人学】7-3.六自由度机器人自干涉检测-圆柱体的旋转变换【附MATLAB代码】
        前言        上一章确定了机械臂等效的圆柱体的上下圆心坐标,这篇文章将解决算法三个核心中的第二个核心:        一 根据机械臂的几何数据以及DH参数,确定机械臂等效的圆柱体的上下圆心坐标。        二 将一个圆柱......
  • 159程序——simulink仿真:三相SPWM逆变电路simulink仿真已提供下载资源
    ......
  • Datawhale X 李宏毅苹果书AI夏令营深度学习进阶(二)
    一.动量法在上一个博客中,我们提到了动量法,现在继续补充如图所示,红色表示负梯度方向,蓝色虚线表示前一步的方向,蓝色实线表示真实的移动量。一开始没有前一次更新的方向,完全按照梯度给指示往右移动参数。负梯度方向跟前一步移动的方向加起来,得到往右走的方向。一般梯度下降走到一......
  • Java经典框架之MyBatis
    一、基本介绍        MyBatis是一个非常流行的Java持久层框架,它提供了简单的方法来处理数据库中的数据。MyBatis可以看作是JDBC的一个薄封装,它简化了JDBC代码的编写,同时提供了强大的功能,如动态SQL、映射自定义对象到数据库记录等。二、核心特性SQLMap......
  • OpenCV(cv::findChessboardCorners())
    目录1.函数原型2.使用场景3.工作原理4.示例4.1角点精细化4.2附加标志5.注意事项cv::findChessboardCorners()是OpenCV提供的一个函数,常用于计算机视觉中的棋盘图像角点检测,特别是相机标定(calibration)和三维重建相关的任务中。1.函数原型boolcv::findChessboard......