c++ - vector容器常用接口模拟实现


一、成员变量

我们通过在堆上申请一个数组空间来进行储存数据,我们的成员变量是三个指针变量,分别指向第一个位置、最后储存有效位置的下一个位置以及数组空间的最后位置的下一个位置。

//为了与stl保持一致使用重命名
typedef T* iterator;
typedef const T* const_iterator;

iterator _start = nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;

在这里插入图片描述

二、常用迭代器接口模拟实现

直接返回数组的开始位置和有效数据的下一个位置即可。

//迭代器
//第一个位置
iterator begin()
{
	return  _start;
}

//有效数据的下一个位置
iterator end()
{
	return _finish;
}

//重载 const
const iterator begin() const
{
	return  _start;
}

const iterator end() const
{
	return _finish;
}

三、一些常用接口模拟

(1)size
求有效数据的个数,用结束位置下一个位置的指针减去第一个位置的指针就是有效数据的个数了。

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

(2)capacity
求容器的容量,用数组空间的最后位置的下一个位置的指针减去第一个位置的指针就是容量的大小了。

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

(3)重载[]

//重载 []
T operator[](size_t i)
{
	//保证i位置符合
	assert(i < size());

	return  *(_start + i);
}

const T operator[](size_t i) const
{
	//保证i位置符合
	assert(i < size());

	return  *(_start + i);
}

(4)reserve
预留空间,一般用于扩容,这里需要手动扩容,再拷贝数据,最后再改变成员变量的指向。

void reserve(size_t n)
{
	//先保存有效数据个数
	size_t _size = size();

	//判断是否需要扩容
	if (n > _size)
	{
		//手动申请空间
		iterator tmp = new T[n];
		//拷贝数据到新空间
		for (size_t i = 0; i < _size; i++)
		{
			*(tmp + i) = *(_start + i);
		}
		//释放掉原来的空间
		delete[] _start;

		//重新改变位置
		_start = tmp;
		_finish = _start + _size;
		_end_of_storage = _start + n;
	}
}

注意:
a.要先保存 size,因为在重新指向时需要_start第一个重新指向新空间,如果此时再去调用size()函数的话,返回的size是不确定的。最终导致_finish 指向错误。

b.就是不能使用memcpy函数进行拷贝,因为memcpy是浅拷贝,当出现数据是自定义类型而且也是需要申请资源的话就会出现重复释放等问题。如数据储存的是string类型。
在这里插入图片描述
所以需要使用深拷贝。
在这里插入图片描述
(5)clear
清空,将_start = _finish即可。

void clear()
{
	_finish = _start;
}

(6)insert
在迭代器位置前插入一个元素,并返回新的position位置。
迭起器失效问题:
插入一个位置可能会扩容,扩容就会导致position位置失效,所以如果需要扩容就先保存好 position 相对 _start的位置。

iterator insert(iterator position, const T val)
{
	//迭代器位置
	assert(position >= _start);
	assert(position <= _finish);

	//空间是否够
	if (_finish == _end_of_storage)
	{	
		//保存相对位置
		size_t _size = position - _start;

		size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapacity);
		
		//重新获取position位置
		position = _start + _size;
	}
	
	//往后移动一位
	iterator end = _finish;
	while (end > position)
	{
		*end = *(end-1);
		--end;
	}
	
	*position = val;
	++_finish;
	
	return position;
}

(7)push_back
尾插入一个元素,这里直接调用insert即可。

void push_back(T x)
{
	insert(_finish, x);
}

(8)erase
删除position位置,返回position位置的值。
这里也可能会存在迭代器失效问题,如缩容(这里不考虑)、最后一个位置。

//删除迭代器
iterator erase(iterator position)
{
	//符合位置
	assert(position >= _start);
	assert(position < _finish);

	//覆盖掉position
	iterator end = position;
	while (end < _finish - 1)
	{
		*end = *(end + 1);
		++end;
	}

	--_finish;
	//这里返回空,因为position已经失效了
	if (position == _finish + 1)
	{
		return nullptr;
	}

	return position;
}

(9)empty
是否空。

bool empty() const
{
	return size() == 0;
}

(10)pop_back
尾删,这里直接调用erase()即可。

void pop_back()
{
	if (empty())
		return;
		
	erase(_finish-1);
}

(11)resize
重新定义大小,n小于实际大小就缩小,n大于实际大小就用val来填充。

//重新定义大小

void resize(size_t n, T val = T())
{

	if (n > capacity())
	{
		reserve(n);
	}

	size_t _size = size();
	if (n > _size)
	{
		for (int i = _size; i < n; i++)
		{
		//直接尾插
			push_back(val);
		}
	}
	else
	{
		_finish = _start + n;
	}

}

(12)swap
交换两个容器。

void swap(vector<T>& x)
{
	//利用std库中的将指针位置交换即可
	std::swap(_start, x._start);
	std::swap(_finish, x._finish);
	std::swap(_end_of_storage, x._end_of_storage);
}

四、默认成员函数

(1)默认构造
无参构造,给了有默认值,这里不用初始化。

vector() {};

用n个val来初始化

vector(size_t n, T val = T())
{
	//先预留空间,这样就不用扩容了
	reserve(n);

	int i = 0;
	while (i < n)
	{
	//尾插
		push_back(val);
		++i;
	}
};

拷贝构造
这里要用深拷贝

vector(vector<T> &x) 
{
	//先预留空间,这样就不用扩容了
	reserve(x.capacity());
	
	//直接将获取的数据插入即可,不用memcpy这种直接拷贝
	vector<T>::iterator it = x.begin();
	while (it != x.end())
	{
	
		push_back(*it);
		++it;
	}
};

用迭代器区间构造,因为可以用其他的容器来初始化,所以这里再用一个模板。

template <class InputIterator>
vector(InputIterator first, InputIterator last)
{
	//先预留空间,这样就不用扩容了
	reserve(last - first);

	while (first < last)
	{
		push_back(*first);
		++first;
	}
}

因为迭代器区间的构造函数与用n个val来初始化构造会冲突。
在这里插入图片描述

为了解决这个问题,使用一个具体一点的n个val来初始化的构造函数

vector(int n, T val = T())
{
	reserve(n);

	int i = 0;
	while (i < n)
	{
		push_back(val);
		++i;
	}
};

(2)析构函数

~vector()
{
	//释放
	delete[]_start;
	_start = _finish = _end_of_storage = nullptr;
}

(3)重载 =

vector<T>& operator=(vector<T> x)
{
	//利用交换函数,x出了该函数作用域就会销毁,所以不用我们手动销毁原来空间了
	swap(x);
	return *this;
}

五、功能测试

(1)内置类型

void test01()
{
	//n个val
	xu::vector<int> v1(2,1);
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;

	//区间
	xu::vector<int> v2(v1.begin(), v1.end());
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v2[i] << " ";
	}
	cout << endl;

	//赋值
	xu::vector<int> v3;
	v3 = v1;
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v3[i] << " ";
	}
	cout << endl;
	

	v1.push_back(2);
	v1.insert(v1.begin(), 0);
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
	v1.pop_back();
	v1.erase(v1.begin());
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;

	v1.resize(10, 5);
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;


}

在这里插入图片描述

(2)自定义类型

void test02()
{
	//n个val
	xu::vector<string> v1(2, "aa");
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;

	//区间
	xu::vector<string> v2(v1.begin(), v1.end());
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v2[i] << " ";
	}
	cout << endl;

	//赋值
	xu::vector<string> v3;
	v3 = v1;
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v3[i] << " ";
	}
	cout << endl;


	v1.push_back("bb");
	v1.insert(v1.begin(), "cc");
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
	v1.pop_back();
	v1.erase(v1.begin());
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;

	v1.resize(10, "ee");
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;

}

在这里插入图片描述

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值