C++第二十二弹---vector深度剖析及模拟实现(下)

2024-06-04 6826阅读

C++第二十二弹---vector深度剖析及模拟实现(下) 第1张

 ✨个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】

目录

1、容量操作

2、内容修改操作

3、打印函数

4、迭代器失效

4.1、什么是迭代器失效

4.2、哪些操作会引起迭代器失效

总结


1、容量操作

size()、capacity()

获取容器的有效数据个数(连续内存空间的指针相减计算的就是间隔的元素个数)和分配给当前空间的大小,以元素个数表示。

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

 reserve(size_t n)

扩容。如果n大于当前容量则扩容,小于等于当前容量则不处理。

void reserve(size_t n)//将容量个数扩大到n
{
	if (n > capacity())//大于容量才扩容
	{
		size_t old_size = size();
		T* tmp = new T[n];
		memcpy(tmp, _start, sizeof(T) * size());
		delete[] _start;//加[]
		_start = tmp;
		//_finish = _start + size();//_start的地址改变了 size()结果变化
		_finish = _start + old_size;
		_endofstorage = _start + n;
	}
}

这里我们开空间完成的是一个深拷贝的过程,用 memcpy 将旧数组中的数据拷贝到新数组,但是memcpy 在这里基于字节的拷贝,即浅拷贝,那么,如果我们vector实例化为string类,这里string类进行浅拷贝会涉及到二次释放等问题。

C++第二十二弹---vector深度剖析及模拟实现(下) 第2张

解决办法:

通过一个循环,使用赋值操作符(自定义类型会调用赋值操作符重载)逐个拷贝旧数组中的元素到新数组。

void reserve(size_t n)//将容量个数扩大到n
{
	if (n > capacity())//大于容量才扩容
	{
		size_t old_size = size();
		T* tmp = new T[n];
		for (size_t i = 0; i  

C++第二十二弹---vector深度剖析及模拟实现(下) 第3张

 注意:

需要提前计算原空间的大小,防止后面计算的大小是错误的,因为扩容的时候_start指针会修改指向,而_finish还指向原空间。

resize(size_t n)

调整容器的大小,使其包含n个元素。

如果n小于当前容器大小,则内容将减少到其前n个元素,删除超出的元素(并销毁它们)。

如果n大于当前容器大小,则通过在末尾插入所需数量的元素来扩展内容,以达到n的大小。如果指定了val,则将新元素初始化为val,否则初始化为缺省值。

如果n也大于当前容器容量,则自动重新分配所分配的存储空间。

void resize(size_t n,const T& val=T())//将容量修改为n个,并初始化为val
{
	if (n > capacity())
	{
		//扩容
		reserve(n);
		while (_finish  

注意:

当 n 小于当前容量时,只需修改 _finish 指向即可,一般情况不缩容,如需缩容,可以调用shrink_to_fit()缩容函数。

2、内容修改操作

push_back()

尾插数据。即在_finish位置插入数据,在插入数据之前需要判断空间是否已满。

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

 pop_back()

尾删数据(有数据才能删)。删除最后一个数据,修改_finish指向即可。

void pop_back()
{
	assert(!empty());
	--_finish;
}

empty()

判断容器是否为空(判断_start与_finish指向是否一致),为空返回true,否则返回false。 

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

insert() 

在pos位置插入数据。

1.使用断言保证在[_start,_finish]区间插入数据

2.判断是否需要扩容,扩容则可能出现迭代器失效情况,则需要提前计算pos 位置与 _start之间的距离。

3.将[pos,_finish)之间的数据都向后挪动一步,再pos位置插入数据。

4.最后返回新的pos位置。

iterator insert(iterator pos, const T& val)//在pos位置插入val
{
	assert(pos >= _start);
	assert(pos = pos)
	{
		*(it + 1) = *it;
		--it;
	}
	//填充数据
	*pos = val;
	++_finish;
    return pos;//返回新的pos位置
}

 erase()

删除pos位置的数据。

1.使用断言保证在[_start,_finish)区间删除数据,此处跟插入不同,不能删除_finsih位置数据

2.将[pos + 1,_finish)之间的数据都向前挪动一步。

iterator erase(iterator pos)//删除pos位置数
{
	assert(pos >= _start);
	assert(pos  

erase 返回值是一个迭代器,指向原来pos位置的下一个位置,即删除操作之后的pos位置。

push_back()  pop_back()

尾插和尾删函数,使用insert()和erase()函数调用。

void push_back(const T& val)
{
	insert(end(), val);//在end()位置插入数据
}
void pop_back()
{
	erase(end() - 1);//删除end()前面位置数据
}

3、打印函数

print_vector()

打印vector容器的数据(任意类型)。

template//函数模板
void print_vector(const vector& v)
{
	//前面加typename则没有问题,表示iterator是一个类型
	//typename vector::iterator it = v.begin();
	auto it = v.begin();//此处使用auto则可以避免此问题
	while (it != v.end())
	{
		cout 

    免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

    目录[+]