C++——vector类及其模拟实现

这篇具有很好参考价值的文章主要介绍了C++——vector类及其模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:前边我们进行的string类的方法及其模拟实现的讲解。这篇文章将继续进行C++的另一个常用类——vector。


一.什么是vector

vector和string一样,隶属于C++中STL标准模板库中的一个自定义数据类型,实际上就是线性表两者之间有着很多相似,甚至相同的方法

但是它们也有着很大的不同:因为vector是线性表,所以他可以存储任意类型的数据,甚至是自定义类型的数据,包括vector本身


二.vector基本框架

#include<assert.h>

namespace Myvector
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		//构造函数
		voctor()
		{}
		//析构函数
		~voctor()
		{
			delete[] _start;
			_strat = _finish = _endofstorage = nullptr;
		}
		//迭代器
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator begin() const
		{
			return _start;
		}
		const_iterator end() const
		{
			return _finish;
		}
		//数据个数
		size_t size() const
		{
			return _finish - _start;
		}
		//空间大小
		size_t capacity() const
		{
			return _endofstorage - _start;
		}
		//[]运算符重载
		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;
	};
}

因为vector允许定义不同类型的数据,所以我们要使用模版来定义类

值得注意的是,在voctor中我们不用传统的size和capacity来定义数据个数和总空间大小,而是都将它们定义为指针类型,通过指针间的相减来得到size和capacity。初始情况下三者均为空指针。

同时我们将T*指针类型重定义为iterator,这是因为vector的本质就是数组,其迭代器就是指针


三.vector常用操作

1.扩容

扩容分为两种方式,只扩容不初始化的reserve,以及扩容并且初始化的resize调整

		//扩容
		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t old_size = size();
				T* tmp = new T[n];
				//memcpy(tmp, _start, sizeof(T) * size());
				for (size_t i = 0; i < old_size; i++)
				{
					tmp[i] = _start[i];
				}
				delete[] _start;
				_start = tmp;
				_finish = old_size + tmp;
				_endofstorage = tmp + n;
			}
		}

扩容较为简单,值得注意的是这里不在使用strcpy,而是通过for循环的方式进行赋值。

		//调整
		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;
			}
		}

对于resize,因为我们需要使用缺省参数,但是由于vector的对象类型不定,甚至是自定义类型,所以我们不能使用0作为缺省参数而应使用匿名对象作为参数,让匿名对象去自动识别类型并调用自己的构造函数形成初始值


2.插入

先来看尾插,与string类似,需要考虑扩容:

		//尾插
		void push_back(const T& val)
		{
			if (_finish == _endofstorage)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}
			*_finish = val;
			_finish++;
		}

测试如下:

C++——vector类及其模拟实现,c++,开发语言

 在来看指定位置的插入先判断pos是否合法,同样需要判断扩容

		//指定位置插入
		void insert(iterator pos, const T& val)
		{
			assert(pos >= _start);
			assert(pos < _finish);
			if (_finish == _endofstorage)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				//扩容要更新pos
				pos = _start + len;
			}
			iterator it = _finish - 1;
			while (it >= pos)
			{
				*(it + 1) = *it;
				--it;
			}
			*pos = val;
			_finish++;
		}

这个指定的位置pos用迭代器比用数字更加方便进行比较,所以建议直接使用迭代器进行插入

有一点值得注意的是,传入的pos是指向原数组的如果进行了扩容,那么原数组被销毁,所有的指针都指向新的数组,所以也需要对pos指针进行更新,否则pos就会成为野指针。 

 测试如下:

C++——vector类及其模拟实现,c++,开发语言


3.遍历

除了上边的for循环遍历外,我们还可以通过迭代器和范围for进行遍历

		vector<int>::iterator it = v.begin();
		while (it != v.end())
		{
			cout << *it << ' ';
			++it;
		}
		cout << endl;
		for (auto e : v)
		{
			cout << e << ' ';
		}
		cout << endl;

测试如下:

C++——vector类及其模拟实现,c++,开发语言


4.删除

首先来看尾删,和顺序表一样,尾删就直接让_finish减1即可,还要注意判断是否为空

		//判空
		bool empty()
		{
			return _start == _finish;
		}
		//尾删
		void pop_back()
		{
			assert(!empty());
			--_finish;
		}

测试如下:

C++——vector类及其模拟实现,c++,开发语言

 再来看指定位置的删除:

		//指定位置删除
		void erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);
			iterator it = pos + 1;
			while (it < _finish)
			{
				*(it - 1) = *it;
				it++;
			}
			_finish--;
		}

测试如下:

C++——vector类及其模拟实现,c++,开发语言


5.交换 

想要实现两个对象之间的交换,其底层实现还是要借助std库中的swap函数

		//交换
		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		}

测试如下: 

C++——vector类及其模拟实现,c++,开发语言 


6.赋值

使用容器的一种必不可少的方法就是相同类型的对象之间的赋值,这就关系到类中的拷贝构造函数了。

我们知道拷贝构造分为浅拷贝和深拷贝后者要关系到指针,显然,voctor类型对象的成员变量都是指针,所以我们必须写出深拷贝构造函数

		//拷贝构造函数
		vector(const vector<T>& v)
		{
			reserve(v.capacity());
			for (auto& e : v)
			{
				push_back(e);
			}
		}

这里我们采用了先开空间,在依次尾插的方式来实现拷贝构造函数,测试如下:

C++——vector类及其模拟实现,c++,开发语言


还可以使用“=”运算符重载的方式进行赋值:

		//=运算符重载
		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}

这个写法非常的高明,假设赋值为:v1 = v2,那么v将作为v2的拷贝与v1进行交换,然后返回v1,而v因为只是一个拷贝,出函数后就会被销毁,所以也不会影响到v2的值,测试如下:

 C++——vector类及其模拟实现,c++,开发语言


 此外,还有一种方式,他可以选择某个对象的部分区间赋值给新的对象,叫做迭代器区间构造

		//迭代器区间构造
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}

 这里要注意,该函数我们把它写成模版函数

类模板的成员函数可以是函数模版,那么写成这样的好处是什么呢?

C++——vector类及其模拟实现,c++,开发语言

能够看出,我们不仅能截取同为vector类型的对象,还能够截取不同的string类型的对象。 


总结

关于vector的分享就到这里啦。

喜欢本篇文章的小伙伴记得一键三连,我们下期再见!文章来源地址https://www.toymoban.com/news/detail-850426.html

到了这里,关于C++——vector类及其模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ 模拟实现vector

    目录 一、定义 二、模拟实现 1、无参初始化 2、sizecapacity 3、reserve 4、push_back 5、迭代器 6、empty 7、pop_back 8、operator[ ] 9、resize 10、insert 迭代器失效问题 11、erase 12、带参初始化 13、迭代器初始化 14、析构函数 15、深拷贝 16、赋值运算符重载 完整版代码测试代码 本次参考SGI版

    2024年02月04日
    浏览(43)
  • 【C++】vector模拟实现

    🚀 作者简介:一名在后端领域学习,并渴望能够学有所成的追梦人。 🚁 个人主页:不 良 🔥 系列专栏:🛸C++  🛹Linux 📕 学习格言:博观而约取,厚积而薄发 🌹 欢迎进来的小伙伴,如果小伙伴们在学习的过程中,发现有需要纠正的地方,烦请指正,希望能够与诸君一同

    2024年02月13日
    浏览(43)
  • [C++]:11.模拟实现vector

    1.vector.h vector.h中其实包含了许多的头文件,我们在cpp中包含文件的时候头文件中还会去展开这四个头文件关于vector类主要在这个stl_vector.h中。 2.stl_vector.h 1.构造: ps:在当前的学习阶段看源码不要一行一行去看因为水平不足所以非常多基本上是看不懂的所以不要去一行一行去

    2024年01月16日
    浏览(43)
  • STL 关于vector的细节,vector模拟实现【C++】

    _start指向容器的头,_finish指向容器当中 有效数据 的下一个位置,_endofstorage指向整个容器的尾 先开辟一块与该容器大小相同的空间,然后将该容器当中的数据一个个拷贝过来即可,最后更新_finish和_endofstorage的值即可。 深拷贝版本一: 注意: 不能使用memcpy函数 , 如果vec

    2024年02月15日
    浏览(46)
  • 【C++ STL】vector模拟实现

    2023年05月17日
    浏览(51)
  • 【C++】vector容器的模拟实现

    目录 一,框架设计 二,构造函数 三,析构函数 四,赋值运算符 五,容器接口的实现 1,迭代器实现 2,“ [] ”运算符的实现 3,swap交换和resize重设大小 4,insert插入和erase删除 介绍:         本文,我们重点实现vector容器的用法,这里要注意的是vector容器可以接纳任意类

    2024年02月02日
    浏览(55)
  • C++ STL vector 模拟实现

    ✅1主页:我的代码爱吃辣 📃2知识讲解:C++之STL 🔥3创作者:我的代码爱吃辣 ☂️4开发环境:Visual Studio 2022 💬5前言:上次我们已经数字会用了vector,这次我们对其底层更深一步挖掘,其中重点是,Vector中一些深浅拷贝问题。 目录 一.Vector模拟实现的整体框架 二. Vector的构

    2024年02月13日
    浏览(35)
  • C++中的vector类模拟实现

    目录 vector模拟实现 vector类设计 vector类构造函数 vector类根据个数构造函数 vector类根据迭代器区间构造函数 vector类拷贝构造函数 vector类赋值运算符重载函数 vector类析构函数 vector类获取有效数据个数函数 vector类获取容量大小函数 vector类begin()函数 vector类end()函数 vector类reser

    2024年04月13日
    浏览(38)
  • C++:vector使用以及模拟实现

    和我们原来讲的string不同, vector并不是类,是一个类模板,加类型实例化以后才是类。 vector是表示 可变大小数组 的序列容器。 像数组一样 ,vector也采用的连续存储空间来存储元素,但是容量可以动态改变。 和其它容器相比,vector访问元素、尾插、尾删较高效,但不在尾部

    2024年02月11日
    浏览(43)
  • 【C++】vector模拟实现+迭代器失效

    铁汁们,今天给大家分享一篇vector模拟实现 + 迭代器失效,来吧,开造⛳️ 指向最后一个空间的下一个位置 💡 iterator _endofstorage 指向存储第一个有效数据空间的位置 💡 iterator _start 指向存储最后一个有效数据空间的下一个位置 💡 iterator _finish 在成员变量声明处给缺省值,

    2024年02月21日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包