当前位置: 首页 > article >正文

C++基础:vector的底层实现

在这里插入图片描述

文章目录

  • 1.类的创建与简单函数的实现
  • 2.vector常用函数的实现
    • 2.1 push_back
    • 2.2 迭代器的实现
    • 2.3 print_vector的实现(迭代器的进阶使用)
    • 2.4 pop_back
    • 2.4 insert(迭代器失效问题)
    • 2.5 erase
    • 2.6 resize

1.类的创建与简单函数的实现

类的创建:

image-20241113085023004

这里我们使用了模版就不能将声明的定义分离了,会出现链接错误

简单函数的实现:

size_t size()
{
	return _finish - _start;
}

size_t capacity()
{
	return _end_of_storage - _start;
}

T& operator[](size_t i)//下标访问
{
	assert(i < size());
	return _start[i];
}

空间的扩容:

if (_finish != _end_of_storage)
{
	*_finish = x;
	++_finish;
}
else
{
	reserve(capacity() == 0 ? 4 : capacity() * 2);
	*_finish = x;
	++_finish;
}

当然也可以写成两个相同的内容放一起:

if (_finish == _end_of_storage)
{
	reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
++_finish;

2.vector常用函数的实现

2.1 push_back

尾插的实现也很简单:

void push_back(const T& x)//加引用是因为遇到vector会进行拷贝
{
	if (_finish != _end_of_storage)
	{
		*_finish = x;
		++_finish;
	}
	else
	{
		reserve(capacity() == 0 ? 4 : capacity() * 2);
		*_finish = x;
		++_finish;
	}

	if (_finish == _end_of_storage)
	{
		reserve(capacity() == 0 ? 4 : capacity() * 2);
	}
	*_finish = x;
	++_finish;
}

但是现在运行程序却崩溃了,这是什么原因呢?

image-20241113090536658

其原因是这里的对size()的调用:

image-20241113091923210

其中_finish为扩容前的而_start为扩容后的

这样进行相减会将新的_start减去无法算到原有的值

更改方法:

  1. 先进行初始化_finish
_finish = tmp + size();
_start = tmp;
_end_of_storage = _start + size();
  1. 将之前的size() 数据留下来:

image-20241113093407316

这样程序就正常了

image-20241113093633712

2.2 迭代器的实现

迭代器和string的实现方法一样

beginend函数写出来就可以实现了:

iterator begin()
{
	return _start;
}
iterator end()
{
	return _finish;
}

image-20241113094314467

2.3 print_vector的实现(迭代器的进阶使用)

为了方便打印我们可以将函数的打印写成一个函数:

typedef const T* const_iterator;

iterator begin() const
{
	return _start;
}
iterator end() const
{
	return _finish;
}

void print_vector(const vector<int>& v)
{
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

1731482956372

我们还可以改创建一个模版让这个函数可以适合任何的数据类型

但是会遇到下面的问题:

image-20241121192943682

template<class T>
void print_vector(const vector<T>& v)
{
    //规定没有实例化的模板里取东西,编译器不能区分const_iterator是类型还是静态成员变量
	typename vector<T>::const_iterator it = v.begin();
    //auto it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

2.4 pop_back

这里先进行判断vector是否为空,不为空直接将_finish--即可

bool empty()
{
	return _finish == _start;
}
void pop_back()
{
	assert(!empty());
	--_finish;
}

2.4 insert(迭代器失效问题)

我们先来看看大体的实现:

1731487476350

void insert(iterator pos,const T& x)
{
	if (_finish == _end_of_storage)
	{
		reserve(capacity() == 0 ? 4 : capacity() * 2);
	}

	iterator end = _finish - 1;
	while (end >= pos)
	{
		*(end - 1) = *(end);
		--end;
	}
	*pos = x;
	_finish++;
}

这里一旦扩容迭代器就失效了

因为迭代器指向的空间被释放导致迭代器失效

1731488575017

我们可以用相对位置来修正这个pos的位置

1731488674888

那如果我们想先找一个数字再它的前面添加呢

我们先来了解一个库里的find函数:

image-20241122191607932

这个函数利用迭代器可以进行查找

那我们写一段代码试一下:

image-20241122193117546

运行测试:

image-20241122193155493

那如果还想对这个p位置进行修改呢?

我们再来试一下:

image-20241122194204475

这里就出问题了

为什么我们的p指向的数字发生了变化,不在指向查找的数字了?

分析一下:

image-20241122224020789

所以==insert以后p就失效了,不要进行访问==

2.5 erase

我们来实现一下这个函数的基本功能:

image-20241122210953699

这里写一个简单的循环删除偶数来测一下:

image-20241122211037215

但是会出现以下两种情况:

  1. 没删干净

image-20241122210939468

原因我们来看一下:

image-20241122211740002

  1. 越界访问了

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

越界的原因:

image-20241122212226649

所以我们默认erase后,迭代器就失效了

2.6 resize

先来看一看实现:

image-20241122222333206

这里我们遇到了T val = T()这里是用一个匿名对象来调用默认构造来进行函数的传参

当理解这个里面的实现很简单


http://www.kler.cn/a/405686.html

相关文章:

  • c语言学习23数组传递到子函数
  • 一次封装,解放双手:Requests如何实现0入侵请求与响应的智能加解密
  • Linux(命令行扩展+命令行历史 大白话+图片)
  • 2024年亚太数学建模竞赛问题C宠物产业及相关产业发展分析与对策
  • SpringCloud多机部署,负载均衡-LoadBalance
  • 一种程序结构设计json,多线程,避免数据竞争
  • Linux 查看端口和进程的常用命令
  • 【优选算法】二分查找
  • 软件测试——自动化测试常见函数
  • 【shell编程】shell基础之for与while循环
  • ElementUI之给el-table实现搜索功能
  • 线性回归学习笔记
  • 【prism】遇到一个坑,分享!
  • Java编程,配置mongoUri连接mongodb时,需对特殊字符进行转义
  • 基于AOA算术优化的KNN数据聚类算法matlab仿真
  • 【网络云计算】2024第47周-每日【2024/11/21】周考-实操题-RAID6实操解析3
  • 麒麟部署一套mysql集群,使用ansible批量部署可以提高工作效率
  • OS 的运行和结构
  • el-table-column自动生成序号在序号前插入图标
  • 利用c语言详细介绍下希尔排序
  • springboot基于java语言的医疗设备管理系统
  • pytorch 的交叉熵函数,多分类,二分类
  • 经济增长初步
  • 初见哈希表容器,及哈希表模拟
  • NLP论文速读(CVPR 2024)|使用DPO进行diffusion模型对齐
  • 昨天刚发布的新机,把前置镜头彻底干没了