【C++庖丁解牛】vector容器的简易模拟实现(C++实现)(最后附源码)

news2024/11/24 17:20:11
🍁你好,我是 RO-BERRY
📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识
🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油

目录

  • 前言
  • vector容器代码实现
    • 内部成员简介
    • 构造函数
    • 拷贝函数
    • 析构函数
    • 迭代器相关
    • 容量相关
    • 元素访问
    • vector的修改操作
  • 源代码


前言

我们前面介绍了vector容器的概念以及对其基本使用进行了介绍,如果你在这里不知道vector是什么以及不知道如何使用的话,可以进入本人主页,在C++专栏里有介绍

为了对小白友好,在这我简单介绍一下

C++中的vector是一个动态数组容器,可以存储不同类型的元素。它提供了一系列的成员函数来方便地操作和管理数组。

以下是C++ vector容器的一些特点和功能:

  1. 动态大小:vector的大小可以根据需要动态调整,可以在运行时添加或删除元素。
  2. 随机访问:可以通过索引直接访问vector中的元素,支持常数时间的随机访问。
  3. 自动内存管理:vector会自动处理内存分配和释放,无需手动管理内存。
  4. 插入和删除:可以在任意位置插入或删除元素,vector会自动调整其他元素的位置。
  5. 迭代器支持:可以使用迭代器遍历vector中的元素。
  6. 动态增长:当vector的容量不足时,会自动重新分配更大的内存空间,以容纳更多的元素。
  7. 元素访问:可以使用下标运算符[]或at()函数来访问元素,也可以使用front()和back()函数分别获取第一个和最后一个元素。

本章节主要对vector容器的手撕实现其简单功能

vector容器代码实现

内部成员简介

命名空间实现与库里vector的隔绝,实现自定义vector

namespace A
{
	template<class T>   //模版实现vector<类型>
	class vector        //vector功能实现
	{
	public:
		// Vector的迭代器是一个原生指针
		typedef T* iterator;
		typedef const T* const_iterator;
		.......           //函数接口实现
		.......
	private:
		iterator _start;		// 指向数据块的开始
		iterator _finish;		// 指向有效数据的尾
		iterator _endOfStorage;  // 指向存储容量的尾
	};
}

构造函数

		vector()
			: _start(nullptr)
			, _finish(nullptr)
			, _endOfStorage(nullptr)
		{}

		vector(size_t n, const T& value = T())
			: _start(nullptr)
			, _finish(nullptr)
			, _endOfStorage(nullptr)
		{
			reserve(n);
			while (n--)
			{
				push_back(value);
			}
		}
	* 理论上讲,提供了vector(size_t n, const T& value = T())之后
	* vector(int n, const T& value = T())就不需要提供了,但是对于:
	* vector<int> v(10, 5);
	* 编译器在编译时,认为T已经被实例化为int,而10和5编译器会默认其为int类型
	* 就不会走vector(size_t n, const T& value = T())这个构造方法,
	* 最终选择的是:vector(InputIterator first, InputIterator last)
	* 因为编译器觉得区间构造两个参数类型一致,因此编译器就会将InputIterator实例化为int
	* 但是10和5根本不是一个区间,编译时就报错了
	* 故需要增加如下构造方法
vector(int n, const T& value = T())
	: _start(new T[n])
	, _finish(_start + n)
	, _endOfStorage(_finish)
{
	for (int i = 0; i < n; ++i)
	{
		_start[i] = value;
	}
}

拷贝函数

		// 若使用iterator做迭代器,会导致初始化的迭代器区间[first,last)只能是vector的迭代器
		// 重新声明迭代器,迭代器区间[first,last)可以是任意容器的迭代器
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		vector(const vector<T>& v)
			: _start(nullptr)
			, _finish(nullptr)
			, _endOfStorage(nullptr)
		{
			reserve(v.capacity());
			iterator it = begin();
			const_iterator vit = v.cbegin();
			while (vit != v.cend())
			{
				*it++ = *vit++;
			}
			_finish = it;
		}

		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}

析构函数

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

迭代器相关

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator cbegin() const
		{
			return _start;
		}

		const_iterator cend() const
		{
			return _finish;
		}

容量相关

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

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

		bool empty() const
		{
			return _start == _finish;
		}

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t oldSize = size();
				// 1. 开辟新空间
				T* tmp = new T[n];

				// 2. 拷贝元素
				// 这里直接使用memcpy会有问题吗?同学们思考下
				//if (_start)
				//	memcpy(tmp, _start, sizeof(T)*size);

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

					// 3. 释放旧空间
					delete[] _start;
				}

				_start = tmp;
				_finish = _start + oldSize;
				_endOfStorage = _start + n;
			}
		}

		void resize(size_t n, const T& value = T())
		{
			// 1.如果n小于当前的size,则数据个数缩小到n
			if (n <= size())
			{
				_finish = _start + n;
				return;
			}

			// 2.空间不够则增容
			if (n > capacity())
				reserve(n);

			// 3.将size扩大到n
			iterator it = _finish;
			_finish = _start + n;
			while (it != _finish)
			{
				*it = value;
				++it;
			}
		}

元素访问

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

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

		T& front()
		{
			return *_start;
		}

		const T& front()const
		{
			return *_start;
		}

		T& back()
		{
			return *(_finish - 1);
		}

		const T& back()const
		{
			return *(_finish - 1);
		}

vector的修改操作

		void push_back(const T& x)
		{
			insert(end(), x);
		}

		void pop_back()
		{
			erase(end() - 1);
		}

		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endOfStorage, v._endOfStorage);
		}

		iterator insert(iterator pos, const T& x)
		{
			assert(pos <= _finish);

			// 空间不够先进行增容
			if (_finish == _endOfStorage)
			{
				//size_t size = size();
				size_t newCapacity = (0 == capacity()) ? 1 : capacity() * 2;
				reserve(newCapacity);

				// 如果发生了增容,需要重置pos
				pos = _start + size();
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}

			*pos = x;
			++_finish;
			return pos;
		}

		// 返回删除数据的下一个数据
		// 方便解决:一边遍历一边删除的迭代器失效问题
		iterator erase(iterator pos)
		{
			// 挪动数据进行删除
			iterator begin = pos + 1;
			while (begin != _finish) 
			{
				*(begin - 1) = *begin;
				++begin;
			}

			--_finish;
			return pos;
		}

源代码

#pragma once

#include <iostream>
using namespace std;
#include <assert.h>


namespace A
{
	template<class T>
	class vector
	{
	public:
		// Vector的迭代器是一个原生指针
		typedef T* iterator;
		typedef const T* const_iterator;

		///
		// 构造和销毁
		vector()
			: _start(nullptr)
			, _finish(nullptr)
			, _endOfStorage(nullptr)
		{}

		vector(size_t n, const T& value = T())
			: _start(nullptr)
			, _finish(nullptr)
			, _endOfStorage(nullptr)
		{
			reserve(n);
			while (n--)
			{
				push_back(value);
			}
		}

		/*
		* 理论上将,提供了vector(size_t n, const T& value = T())之后
		* vector(int n, const T& value = T())就不需要提供了,但是对于:
		* vector<int> v(10, 5);
		* 编译器在编译时,认为T已经被实例化为int,而10和5编译器会默认其为int类型
		* 就不会走vector(size_t n, const T& value = T())这个构造方法,
		* 最终选择的是:vector(InputIterator first, InputIterator last)
		* 因为编译器觉得区间构造两个参数类型一致,因此编译器就会将InputIterator实例化为int
		* 但是10和5根本不是一个区间,编译时就报错了
		* 故需要增加该构造方法
		*/
		vector(int n, const T& value = T())
			: _start(new T[n])
			, _finish(_start + n)
			, _endOfStorage(_finish)
		{
			for (int i = 0; i < n; ++i)
			{
				_start[i] = value;
			}
		}

		// 若使用iterator做迭代器,会导致初始化的迭代器区间[first,last)只能是vector的迭代器
		// 重新声明迭代器,迭代器区间[first,last)可以是任意容器的迭代器
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		vector(const vector<T>& v)
			: _start(nullptr)
			, _finish(nullptr)
			, _endOfStorage(nullptr)
		{
			reserve(v.capacity());
			iterator it = begin();
			const_iterator vit = v.cbegin();
			while (vit != v.cend())
			{
				*it++ = *vit++;
			}
			_finish = it;
		}

		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}

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

		/
		// 迭代器相关
		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator cbegin() const
		{
			return _start;
		}

		const_iterator cend() const
		{
			return _finish;
		}

		//
		// 容量相关
		size_t size() const
		{
			return _finish - _start;
		}

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

		bool empty() const
		{
			return _start == _finish;
		}

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t oldSize = size();
				// 1. 开辟新空间
				T* tmp = new T[n];

				// 2. 拷贝元素
				// 这里直接使用memcpy会有问题吗?同学们思考下
				//if (_start)
				//	memcpy(tmp, _start, sizeof(T)*size);

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

					// 3. 释放旧空间
					delete[] _start;
				}

				_start = tmp;
				_finish = _start + oldSize;
				_endOfStorage = _start + n;
			}
		}

		void resize(size_t n, const T& value = T())
		{
			// 1.如果n小于当前的size,则数据个数缩小到n
			if (n <= size())
			{
				_finish = _start + n;
				return;
			}

			// 2.空间不够则增容
			if (n > capacity())
				reserve(n);

			// 3.将size扩大到n
			iterator it = _finish;
			_finish = _start + n;
			while (it != _finish)
			{
				*it = value;
				++it;
			}
		}

		///
		// 元素访问
		T& operator[](size_t pos)
		{
			assert(pos < size());
			return _start[pos];
		}

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

		T& front()
		{
			return *_start;
		}

		const T& front()const
		{
			return *_start;
		}

		T& back()
		{
			return *(_finish - 1);
		}

		const T& back()const
		{
			return *(_finish - 1);
		}
		/
		// vector的修改操作
		void push_back(const T& x)
		{
			insert(end(), x);
		}

		void pop_back()
		{
			erase(end() - 1);
		}

		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endOfStorage, v._endOfStorage);
		}

		iterator insert(iterator pos, const T& x)
		{
			assert(pos <= _finish);

			// 空间不够先进行增容
			if (_finish == _endOfStorage)
			{
				//size_t size = size();
				size_t newCapacity = (0 == capacity()) ? 1 : capacity() * 2;
				reserve(newCapacity);

				// 如果发生了增容,需要重置pos
				pos = _start + size();
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}

			*pos = x;
			++_finish;
			return pos;
		}

		// 返回删除数据的下一个数据
		// 方便解决:一边遍历一边删除的迭代器失效问题
		iterator erase(iterator pos)
		{
			// 挪动数据进行删除
			iterator begin = pos + 1;
			while (begin != _finish) {
				*(begin - 1) = *begin;
				++begin;
			}

			--_finish;
			return pos;
		}
	private:
		iterator _start;		// 指向数据块的开始
		iterator _finish;		// 指向有效数据的尾
		iterator _endOfStorage;  // 指向存储容量的尾
	};
}

/// /
/// 对模拟实现的vector进行严格测试
void TestBitVector1()
{
	A::vector<int> v1;
	A::vector<int> v2(10, 5);

	int array[] = { 1,2,3,4,5 };
	A::vector<int> v3(array, array + sizeof(array) / sizeof(array[0]));

	A::vector<int> v4(v3);

	for (size_t i = 0; i < v2.size(); ++i)
	{
		cout << v2[i] << " ";
	}
	cout << endl;

	auto it = v3.begin();
	while (it != v3.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

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

void TestBitVector2()
{
	A::vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	cout << v.front() << endl;
	cout << v.back() << endl;
	cout << v[0] << endl;
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

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

	v.insert(v.begin(), 0);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	v.erase(v.begin() + 1);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

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

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

相关文章

xss.haozi.me靶场“0x0B-0x12”通关教程

君衍. 一、0x0B 实体编码绕过二、0x0C script绕过三、0x0D 注释绕过四、0X0E ſ符号绕过五、0x0F 编码解码六、0x10 直接执行七、0x11 闭合绕过八、0x12 闭合绕过 一、0x0B 实体编码绕过 我们首先构造payload进行测试&#xff1a; 这里我们可以看到全部转为了大写&#xff0c…

低压线性恒流LED恒流驱动芯片SM15633EH:用于洗墙灯和线条灯

洗墙灯和线条灯是两种常见的LED照明产品&#xff0c;它们都需要使用LED恒流驱动芯片来确保稳定、可靠的电流供应&#xff0c;从而保证LED的使用寿命和亮度。 对于洗墙灯而言&#xff0c;由于其发出的光线需要覆盖较大的区域&#xff0c;因此需要使用较大功率的LED芯片&#xf…

rust入门(1)创建项目

安装 vscode 安装插件 rust-analyzerNative Debug vscode 配置自动格式化代码 settings.json{"editor.defaultFoldingRangeProvider": null,"[rust]": {"editor.defaultFormatter": "rust-lang.rust-analyzer", // Makes the magi…

mysql5.6---windows和linux安装教程和忘记密码怎么办

一、windows安装 1.完成解压 解压完成之后将其放到你喜欢的地址当中去&#xff0c;这里我默认放在了D盘&#xff0c;这是我的根目录 2.配置环境变量 我的电脑->属性->高级->环境变量->系统变量 选择PATH,在其后面添加: (注意自己的安装地址) D:\mysql-5.6.49…

在域控批量导出用户及其所在路径的信息

在Windows Server的Active Directory环境中&#xff0c;要批量导出用户及其所在OU&#xff08;组织单位&#xff09;的信息&#xff0c;可以使用PowerShell命令来实现。以下是一个简单的示例&#xff1a; Get-ADUser -Filter * -Properties CanonicalName | Select-Object Nam…

CCCorelib 点云球形特征(CloudCompare内置算法库)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 这里基于每个点的邻域协方差来获取点云中具有的球形几何特征的点,计算方式如下图所示: 二、实现代码 // CloudCompare #include <CCCoreLib/PointCloudTpl.h> #include <CCCoreLib/

数据库基础理论知识

1.基本概念 数据(Data)&#xff1a;数据库存储的基本对象。数字、字符串、图形、图像、音频、视频等数据库(DB)&#xff1a;在计算机内&#xff0c;永久存储、有组织、可共享的数据集合数据库管理系统(DBMS)&#xff1a;管理数据库的系统软件数据库系统(DBS):DBDBMSDBADBAP 数…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《考虑碳捕集机组与氢储能系统协调运行的源荷储低碳经济调度》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

机器人ChatGPT来了,80亿参数、前OpenAI人员经数年打造

严格地说&#xff0c;是“拾取与放置任务”版本的ChatGPT来了。除了自然语言交流&#xff0c;还能像Sora一样生成视频。 有了机器人基础模型RFM-1&#xff0c;使用简单英语就能指导机器人完成拣选工作。 机器人 AI 公司 Covariant CEO Peter Chen ‍坐在一个聊天机器人面前&…

图像分割损失函数

为什么要乘以2&#xff0c;是为了让DICE的值域在0和1之间 优化&#xff1a;两种LOSS相加 Focus loss:

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的田间杂草检测系统(深度学习模型+UI界面+Python代码+训练数据集)

摘要&#xff1a;开发用于田间杂草识别的系统对提高农业运营效率和提升作物产出至关重要。本篇文章详尽阐述了如何应用深度学习技术开发一个用于田间杂草识别的系统&#xff0c;并附上了完备的代码实现。该系统基于先进的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5…

提前爆料:绝地求生七周年预告片餐厅改版,七周年主题战术手套

七周年预告片刚刚在官博上线&#xff0c;让我们一起逐帧分析一下都有哪些皮肤吧。 开局就是一个七周年喷漆 然后出生岛手里会拿着七周年的蛋糕&#xff0c;互相丢。 艾伦格的餐厅们进行改版&#xff0c;成为七周年主题 餐厅内有一个七周年的饮料机&#xff0c;不知道是不是和米…

浅淡 C++ 与 C++ 入门

我们知道&#xff0c;C语言是结构化和模块化的语言&#xff0c;适用于较小规模的程序。而当解决复杂问题&#xff0c;需要高度抽象和建模时&#xff0c;C语言则不合适&#xff0c;而C正是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库…

C++的类和对象(六):友元、内部类

目录 友元 友元函数 友元类 内部类 匿名对象 拷贝对象时的一些编译器优化 再次理解类和对象 友元 基本概念&#xff1a;友元提供了一种突破封装的方式&#xff0c;有时提供了便利&#xff0c;但是友元会增加耦合度&#xff0c;破坏了封装&#xff0c;所以友元不宜多用&…

数据结构 第1章:绪论

文章目录 1. 绪论1.1. 数据结构 1.2. 算法1.2.1. 算法的基本概念1.2.2. 算法的时间复杂度1.2.3. 算法的空间复杂度 1. 绪论 程序 数据结构 算法 1.1. 数据结构 数据&#xff1a;是对客观事物的符号表示&#xff0c;在计算机科学中是指所有能输入到计算机中并被计算机程序处理…

【YOLOv9】训练模型权重 YOLOv9.pt 重新参数化轻量转为 YOLOv9-converted.pt

【YOLOv9】训练模型权重 YOLOv9.pt 重新参数化轻量转为 YOLOv9-converted.pt 1. 模型权重准备2. 模型重新参数化2.1 文件准备2.2 参数修改2.3 重新参数化过程 3. 重新参数化后模型推理3.1 推理超参数配置3.2 模型推理及对比 4. onnx 模型导出&#xff08;补充内容&#xff09;4…

MathType7最新软件产品秘钥2024中文版

MathType 7是一款功能强大的数学公式编辑器&#xff0c;专为教育工作者、学生、科研人员以及任何需要处理数学公式的人群设计。以下是对MathType 7的详细介绍&#xff1a; 一、功能特点&#xff1a; 广泛的符号和模板支持&#xff1a;MathType 7支持各种数学符号、公式、方程…

OpenAI:ChatGPT API 文档之 Embedding

在自然语言处理和机器学习领域&#xff0c;"embeddings" 是指将单词、短语或文本转换成连续向量空间的过程。这个向量空间通常被称为嵌入空间&#xff08;embedding space&#xff09;&#xff0c;而生成的向量则称为嵌入向量&#xff08;embedding vector&#xff0…

基于支持向量机SVM的沉降预测,SVM详细原理,Libsvm详解

目录 支持向量机SVM的详细原理 SVM的定义 SVM理论 Libsvm工具箱详解 简介 参数说明 易错及常见问题 完整代码和数据下载链接:基于支持向量机SVM的沉降预测资源-CSDN文库 https://download.csdn.net/download/abc991835105/88947544 SVM应用实例,基于支持向量机SVM的沉降预测…

LED基础知识分享(一)

大家好&#xff0c;我是砖一。 今天给大家分享一下&#xff0c;LED的基础知识&#xff0c;有照明行业&#xff0c;或者对LED感兴趣的朋友&#xff0c;可以学习一下&#xff0c;希望对你有用~ 一&#xff0c;什么是LED (Light Emitting Diode)? 1&#xff0c;LED是一种发出某…