C++-Vector容器常用接口的模拟实现


目录

一.vector类对象的实例化

二.实现尾插功能

三.insert和erase产生的迭代器失效的问题

四.resize

五.拷贝构造和赋值运算符的重载


        库中定义的vector类模板在分配空间的时候使用的是内存池,在这里我们使用的是new来模拟实现。

        vector容器可以替代掉string容器吗?

                不可以!因为string是专门用来处理字符串的 ,但是vector不是,再有在操作字符串时string会默认自动在结尾加‘\0’用来表示字符串的结尾,但是vector不会,这样可以更好的去兼容c语言,string有很多专用接口,vector不支持。

一.vector类对象的实例化

  当我们看到一个类对象的时候首先应该想到一副图。

  我们对vector对象的操作都是在对这个线性表的操作。

        类成员变量和构造函数和析构函数:

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

    //成员函数
    //默认成员函数
    //构造函数
    vector()
	    : start(nullptr)
	    , finish(nullptr)
	    , end_of_storage(nullptr)
        {}

    //析构函数
    ~vector()
    {
	    start = nullptr;
	    finish = nullptr;
	    end_of_storage = nullptr;
    }

private:
	//成员变量
	iterator start;
	iterator finish;
	iterator end_of_storage;
};

        在类模板中还可以定义函数模板。

二.向数组中插入数据

void reserve(size_t rsize)
{
	if (rsize> capacity())
	{
		//保存原数组中的数据量
		size_t nums = size();

		//开辟新的空间
		iterator tmp = new value_type[rsize + 1];

		if (start)
		{
			//将原数组中的数据拷贝到新申请的空间中去
			//但是此时会有一个问题就是如果vector模板实例化的类型是内置类型,那么没有问题,
			//但是如果是自定义类型那么就会产生深浅拷贝的问题。
			//memcpy(tmp, start, sizeof(value_type) * nums);
			//解决办法
			int i_i = 0;
			for (i_i = 0; i_i < nums; i_i++)
			{
				tmp[i_i] = start[i_i];
			}

			//释放原空间
			delete[] start;
		}

		//更改参数
		start = tmp;
		finish = start + nums;
		end_of_storage = start + rsize;
	}
}

这里拷贝有一个问题:

        如果vector顺序表中的每一个元素是内置类型那么没问题,使用memcpy进行浅拷贝不会产生任何问题。

        但是:

        像这样使用自定义类型就会出现问题了

        会产生这样的问题,此时我们在释放原空间,那么不就相当于产生了野指针的情况吗。

        解决方法

        通过调用自定义类型的赋值重载来解决这个问题!

三.实现vector数据的遍历

//实现迭代器
iterator begin()
{
	return start;
}
iterator end()
{
	return finish;
}
const_iterator begin()const
{
	return start;
}
const_iterator end()const
{
	return finish;
}

//实现v[]
value_type operator[](size_t index)
{
	assert(index > 0 && index <= size());

	return *(start + index - 1);
}

//实现返回当前数组的最大存储空间的大小
size_t capacity()
{
	return end_of_storage - start;
}

//实现返回当前数组的数据量
size_t size()
{
	return finish - start;
}

 四.insert和erase产生的迭代器失效的问题

    insert方法中内部产生的迭代器失效问题:因为空间不足要扩容,而保存迭代器的变量中还保存原空间的地址,这样就造成了迭代器的失效。

    而外部迭代器的失效的问题是通过返回迭代器的方式来解决的。

//实现insert和erase
iterator insert(iterator pos, const value_type& data)
{
	//检查插入位置是否正确
	assert(pos >= start && pos < finish);

	//判断存储空间是否足够
	if (finish == end_of_storage)
	{
		//记录数据位置,防止发生迭代器失效的问题
		size_t length = pos - start;

		//开辟空间
		reserve(capacity() == 0 ? 4 : capacity() * 2);

		//获取在新开辟空间的位置
		pos = start + length;
	}

	//挪动数据
	iterator end = finish - 1;
	while (end >= pos)
	{
		*(end + 1) = *(end);
		end--;
	}

	//放入数据
	*pos = data;
	finish++;

	//防止迭代器失效,返回此时的pos
	return pos;
}
iterator erase(iterator pos)
{
	//判断数据是否正确
	assert(pos >= start && pos < finish);

	//挪动删除数据
	iterator tmp = pos;
	while (tmp < (finish - 1))
	{
		*(tmp) = *(tmp + 1);
		tmp++;
	}
	finish--;

	//防止迭代器失效
	return pos;
}

        erase这里虽然不会产生上述insert的问题,但是因为不同环境的检查迭代器失效的方式不同,所以在erase后也会产生迭代器失效的问题。通过返回迭代器的方式解决问题。

四.resize

        对于resize的第二个参数:因为resize方法是调整一段空间,并且如果扩容会对新空间进行初始化,所以不同的类型的顺序表的初始化不同,所以有

这里value_type()是一个匿名对象,匿名对象具有常性,所以要使用const引用,且要保证具有默认构造函数,那内置内信哪里来的默认构造函数,这里注意C++在有了模板后对内置类型进行了升级,内置类型也有了默认构造函数,

五.拷贝构造和赋值运算符的重

//拷贝构造
vector(const vector<T>& v)
	: start(nullptr)
	, finish(nullptr)
	, end_of_storage(nullptr)
{
	reserve(v.capacity());

	for (auto e : v)
	{
		push_back(e);
	}
}

//赋值重载
vector<T>& operator=(vector<T> v)
{
	Swap(v);

	return *this;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值