简单模拟vector的特性

2022-08-07 11:36:31

        阅读《STL源码剖析》有感,根据vector特性,基于数组,手动模拟一个vector。首先定义几个typedef,方便指针的定义。

template<typename T>
class Vector
{
public:
	typedef T value_type;
	typedef value_type* pointer;
	typedef value_type* iterator;
	typedef value_type& reference;
public:
	typedef T value_type;
	typedef value_type* pointer;
	typedef value_type* iterator;
	typedef value_type& reference;

protected:
	iterator start; //表示目前使用空间的头
	iterator finish; //目前使用空间的尾
	iterator end_of_storage; //目前可用空间的尾
};

        定义一个迭代器类型iterator(指针),之后定义三个迭代器,start(表示目前使用空间的头)、finish(目前使用空间的尾)、end_of_storage(目前可用空间的尾)。之后通过对指针的操作,以及数组的扩容模拟vector。全部源码如下:

//Vector.h
#pragma once
#include <memory>
template<typename T>
class Vector
{
public:
	typedef T value_type;
	typedef value_type* pointer;
	typedef value_type* iterator;
	typedef value_type& reference;
public:
	Vector(int lenght = 0) :start(nullptr), finish(nullptr), end_of_storage(nullptr)
	{
		start = new value_type[lenght];
		finish = start;
		end_of_storage = &start[lenght];
	}
	~Vector()
	{
		delete[]start;
		start = nullptr;
	}
public:
	iterator begin()
	{
		return start;
	}

	iterator end()
	{
		return finish;
	}

	int size()
	{
		return static_cast<int>(end() - begin());
	}

	void push_back(const T & x)
	{
		if (finish != end_of_storage)
		{
			*finish = x;
			finish++;
		}
		else
		{
			int num = size();
			if (num <1)
			{
				iterator newstart = new value_type[2];
				delete []start;
				start = nullptr;
				start = newstart;
				finish = start;
				end_of_storage = &start[2];
				*finish = x;
				finish++;
			}
			else
			{
				iterator newstart = new value_type[num * 2];
				memcpy(newstart,start, sizeof(value_type) * num);
				delete[]start;
				start = nullptr;
				start = newstart;
				finish = start+num;
				*finish = x;
				end_of_storage = &start[num * 2];
				finish++;
			}
		}
	}
	
	void pop_back()
	{
		if (finish != start)
		{
			finish--;
		}
		
	}

	reference operator[](int n)
	{
		return *(begin() + n);
	}

	iterator erase( const iterator  position)
	{
		if (position + 1 != end())
		{
			int num = static_cast<int>(finish - (position+1));
			memmove(position, position+1, sizeof(value_type)*(num));
		}
		--finish;
		return position;
	}

    iterator erase(iterator  first, iterator  last)
	{
		if (first + 1 != end())
		{
			int num = static_cast<int>(finish - last);
			memmove(first, last, sizeof(value_type)*(num));
			finish = first - num;
		}
		return first;
	}

	void clear()
	{
		erase(begin(),end());
	}

	int capacity()
	{
		return static_cast<int>(end_of_storage - begin());
	}

protected:
	iterator start; //表示目前使用空间的头
	iterator finish; //目前使用空间的尾
	iterator end_of_storage; //目前可用空间的尾
private:

};

        在vector的构造函数中,通过传入的参数,开辟空间大小。默认参数为零。在构造函数中,start和finish指针,指向开辟空间的首地址,end_of_storage指向最后的地址。begin()和end() ,分贝返回start指针和finish指针。push_back()函数,在传入值时,所占空间已满,开辟之前二倍的空间,并将之前的值拷贝到刚开辟的空间中,同时,释放原来的空间,finish指针向后移动。pop_back()函数实现较为简单,将finish指针向前移动。其他的各个操作,都是对指针操作得到结果。测试代码:

#include <iostream>
#include "Vector.h"

int main()
{
	Vector<int> vector;

	vector.push_back(1);
	vector.push_back(2);
	vector.push_back(3);
	vector.push_back(4);
	vector.push_back(5);

	int temp = vector.size();
	int temp1 = vector.capacity();
	printf("输入的元素:\n");
	for (Vector<int>::iterator item = vector.begin();item !=vector.end();item++)
	{
		printf("%d\n",*item);
	}
	printf("所存数据 = %d,空间所占大小 = %d\n", temp, temp1);
	vector.pop_back();
	vector.pop_back();
	vector.pop_back();
	vector.pop_back();
	int temp3 = vector.size();
	int temp4 = vector.capacity();
	printf("出栈后剩余的元素:\n");
	for (Vector<int>::iterator item = vector.begin(); item != vector.end(); item++)
	{
		printf("%d\n", *item);
	}
	printf("所存数据 = %d,空间所占大小 = %d\n", temp3, temp4);
	return 0;
}

输出结果:

        最后聊聊erase() 成员函数,此函数,在STL vector中,通过vs2015测试时,通过迭代器删除一个元素时,不管它 “ * ”取值,还是++操作,都会崩溃。

for (std::vector<int>::iterator item =hvector.begin();item!=hvector.end();item++)
	{
		printf("%d\n", *item);
		if (*item == 3)
		{
			hvector.erase(item);
			 int i = *item;//崩溃
		}

        //item++时崩溃
	}

        网上更多的说法,item被删除掉,成了野指针。但是当我看见《STL源码剖析》时,erase()的实现如下:

在这里只是进行了位置的偏移,同时释放掉最后一个元素。(至此,我在模拟时,也进行了位置的偏移), 从这里可以看到,并不是因为野指针的缘故。

参看这篇博客C++ vector容器erase操作后iterate失效真相 ,这里作者提到vs中erase()参数是const_iterator,所以++时会报错。我没理解到作者的观点。各位读者知道后,请互相交流学习一下,十分感激。网上众说纷纭,自己也没找到很有说服力的答案。至此,技术有限,这里留下一个疑点。我怀疑可能是,内存发生了改动,导致迭代器失效报错。

如果作者不想复制粘贴,可下载:

源码:模拟vector的简易实现-C++文档类资源-CSDN下载

  • 作者:梦想患者
  • 原文链接:https://blog.csdn.net/qq_39884728/article/details/119875827
    更新时间:2022-08-07 11:36:31