STL库 —— vector 的编写

一、成员变量

二、容量成员

2.1 size 函数

我们在定义私有成员时就会发现,其中 _finish 相当于 string 中的 size 的地址, _endofstorage 相当于 string 中的 capacity 的地址,所以 size 函数和 capacity 函数其实基本没有改变。

size_t size()
{
	return _finish - _start;
}

2.2 capacity 函数

size_t capacity()
{
	return _endofstorge - _start;
}

2.3 reserve 函数

void reserve(size_t n)
{
	if (n >= capacity())
	{
		T* tmp = new T[n];
		size_t _size = size();
		memcpy(tmp, _start, _size * sizeof(T));
		delete[] _start;

		_start = tmp;
		_finish = tmp + _size;
		_endofstorge = tmp + n;
	}
}

有了reserve函数,我们就可以先写一个push_back来方便后续测试

void push_back(T tmp)
{
	size_t _size = size();
	size_t n = capacity() == 0 ? 4 : 2 * capacity();
	reserve(n);
	*_finish = tmp;
	_finish++;
}

2.4 resize 函数


因为reseve的性质,上述的第二种和第三种情况我们可以合并成一种

void resize(size_t n, T val = T())
{
	int _size = size(), _capacity = capacity();
	if (n < _size)
	{
		_finish = _start + n;
	}
	else
	{
		reserve(n);
		while (_size++ < n)
		{
			*_finish = val;
			_finish++;
		}
	}
}

测试代码:

void test_resize()
{
	my_vector v2;
	v2.push_back(1);
	v2.push_back(2);
	v2.push_back(3);
	v2.print_vector();

	v2.resize(20, 10);
	v2.print_vector();
			
	v2.resize(5, 10);
	v2.print_vector();
			
	v2.push_back(1);
	v2.push_back(2);
	v2.print_vector();
			
	v2.resize(2);
	v2.print_vector();
	v2.push_back(1);
	v2.push_back(2);
	v2.print_vector();
}

三、迭代器

3.1 begin() 函数

typedef const T* const_iterator;

iterator begin()
{
	return _start;
}

const_iterator begin() const
{
	return _start;
}

3.2 end() 函数

iterator end()
{
	return _finish;
}

const_iterator end() const
{
	return _finish;
}

四、 元素访问成员

T& operator[](size_t pos)
{
	assert(pos < size());
	return _start[pos];
}

测试代码:

void test_operator_()
{
	my_vector<int> v3;
	v3.push_back(1);
	v3.push_back(2);
	v3.push_back(3);
	v3.push_back(4);
	v3.push_back(5);
	v3.push_back(6);
	v3.push_back(7);
	v3.push_back(8);
	v3.push_back(9);
	v3.push_back(0);
	for (int i = 0; i < v3.size(); i++)
	{
		std::cout << v3[i] << std::endl;
	}
			
}

五、 修饰符函数

4.1 insert 函数

先编写 insert 函数,是为了让后面的 push_back 函数有更好的写法。

下面是使用索引进行指定位置插入: 

void insert(int pos, const T& val)
{
	assert(pos <= size());
	size_t _size = size(), _capacity = capacity();
	if (_size == _capacity) reserve(_capacity == 0 ? 4 : 2 * _capacity);
	for (int i = _size; i > pos; i--)
	{
		*(_start + i) = *(_start + i - 1);
	}
	*(_start + pos) = val;
	_finish++;
}
//测试样例
void test_insert1()
{
	my_vector<int> v4;
	v4.push_back(1);
	v4.push_back(2);
	v4.push_back(3);
	v4.push_back(4);
	v4.push_back(5);
	v4.insert(3, 0);
	for (int i = 0; i < v4.size(); i++)
	{
		std::cout << v4[i] << std::endl;
	}
}

但是在库中,使用的是迭代器来定位插入元素的位置:

其中,要注意扩容后对 pos 的更新!迭代器定位插入元素时可以使用 [begin() + i] 或 [end() ...] 来传入参数。
 

void insert(Iterator pos, const T& val)
{
	assert(pos >= _start);
	assert(pos <= _finish);

	if (_finish == _endofstorage)
	{
		size_t len = pos - _start;
		reserve(capacity() == 0 ? 4 : capacity() * 2);

		// 如果扩容了要更新pos
		pos = _start + len;
	}

	Iterator it = _finish - 1;
	while (it >= pos)
	{
		*(it + 1) = *it;
		--it;
	}
	*pos = val;
	++_finish;
}
//测试样例
void test_insert2()
{
	my_vector<int> v5;
	v5.push_back(1);
	v5.push_back(2);
	v5.push_back(3);
	v5.push_back(4);
	v5.push_back(5);
	v5.insert(v5.begin() + i, 0);
	for (int i = 0; i < v5.size(); i++)
	{
		std::cout << v5[i] << std::endl;
	}
}

4.2 push_back 函数 

除了上面的传统写法外,我们的 push_back 也可以借助 insert 来服用:

void push_back2(T tmp)
{    
    //借助insert1
	insert(size(), tmp);
    /借助insert2
    insert(end(), tmp);
}

4.3 erase 函数

因为官方是使用的 iterator 所以这里也只是用 iterator 的方法:

void erase(Iterator pos)
{
	assert(pos >= _start);
	assert(pos < _finish);

	Iterator it = pos + 1;
	while (it < _finish)
	{
		*(it - 1) = *it;
	    ++it;
	}
	--_finish;
}

4.4 pop_back 函数

同 push_back ,可以复用 erase 函数。

void pop_back()
{
	erase(end() - 1);
}

4.5 swap 函数

这里需要注意参数要设置成引用的格式!

void swap(my_vector& v)
{
	std::swap(_start, v._start);
	std::swap(_finish, v._finish);
	std::swap(_endofstorage, v._endofstorage);
}
//测试代码
void test_swap()
{
	my_vector<double> v7;
	v7.push_back2(1.1);
	v7.push_back2(2.2);
	v7.push_back2(3.3);
	v7.print_vector();
	my_vector<double> v8;
	v8.push_back1(3.3);
	v8.push_back1(6.6);
	v8.push_back1(9.9);
	v8.print_vector();

	v7.swap(v8);
	v7.print_vector();
}

4.6 clear 函数

void clear()
{
	_start = _finish = _endofstorage = nullptr;
}
//测试代码
void test_clear()
{
	my_vector<double> v9;
	v9.push_back2(1.1);
	v9.push_back2(2.2);
	v9.push_back2(3.3);
	v9.print_vector();
	v9.clear();
	v9.print_vector();
	v9.push_back1(6.6);
	v9.print_vector();
}

六、成员函数

6.1 构造函数

全缺省构造函数直接使用了“类内初始化器”,即 "In-Class Member Initializer" 

private:
	Iterator _start = nullptr;
	Iterator _finish = nullptr;
	Iterator _endofstorage = nullptr;

标准构造函数,它接受一个大小参数 n 和一个默认值 val ,并创建一个大小为 n 的 vector ,如下

my_vector(size_t n, const T& val = T())
{
	reserve(n);
	for (size_t i = 0; i < n; i++)
	{
		push_back(val);
	}
}

还有两种 C++11 及之后引入的构造函数如下:

1. 使用初始化列表构造,允许使用花括号 {} 来初始化对象,如

my_vector<int> v = {1, 2, 3, 4, 5};  // 调用 `vector(initializer_list<T> il)` 构造函数

其代码为:

my_vector(initializer_list<T> il)
{
	reserve(il.size());
	for (auto& e : il)
	{
		push_back(e);
	}
}

 2. 范围构造函数,它接收两个迭代器,表示要复制的元素的范围,如

std::vector<int> source = {1, 2, 3, 4, 5};
my_vector<int> v(source.begin(), source.end());  // 调用 `vector(InputIterator first, InputIterator last)` 构造函数

其代码为:

template <class InputIterator>        
my_vector(InputIterator first, InputIterator last)
{
	while (first != last)
	{
		push_back(*first);
		++first;
	}
}

 6.2 析构函数

~my_vector()
{
	delete[] _start;
	_start = _finish = _endofstorage = nullptr;
}

6.3 拷贝构造函数

my_vector(const my_vector<T>& v)
{
	reserve(v.capacity());
	for (auto& e : v)
	{
		push_back(e);
	}
}

6.3 = 的重载

注意这里的传入参数并没有使用引用,这也是可以直接使用 swap 的原因:

my_vector<T>& operator=(my_vector<T> v)
{
	swap(v);
	return *this;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/523789.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯备赛合集

蓝桥杯 - 穿越雷区 解题思路&#xff1a; dfs 方法一&#xff1a; import java.util.Scanner;public class Main {static char[][] a;static int[][] visited;static int[] dx { 0, 1, 0, -1 };static int[] dy { 1, 0, -1, 0 };static long min Long.MAX_VALUE;static …

DtDay1

1.导图 2.mywidget.cpp源码 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置窗口大小this->resize(900,700);//设置窗口标题this->setWindowTitle("玄冥科技");this->setWindowIcon(QIcon("C:\\Users…

3D打印技术引领压铸模具制造新变革

随着工业4.0浪潮的席卷&#xff0c;3D打印技术以其独特优势&#xff0c;正逐渐成为新一轮工业革命中的璀璨明星。这一技术不仅为“中国制造”向“中国智造”的转型提供了强大动力&#xff0c;也为压铸模具这一铸造行业的重要分支带来了前所未有的变革。 压铸模具&#xff0c;作…

day02 51单片机

51单片机学习 1闪烁LED 1.1 需求描述 这个案例,我们要让P00引脚对应的LED按照1秒闪烁1次。 1.2 硬件设计 1.1 软件设计 1)LED闪烁的代码 想让LED闪烁,就需要P00的值不断在0和1之间循环变化。实现这一功能的代码也很简单: #include <STC89C5xRC.H> //包含STC89…

[lesson10]C++中的新成员

C中的新成员 动态内存分配 C中的动态内存分配 C中通过new关键字进行动态内存申请C中的动态内存申请是基于类型进行的delete关键字用于内存释放 new关键字与malloc函数的区别 new关键字是C的一部分malloc是由C库提供的函数new以具体类型位单位进行内存分配malloc以字节位单位…

Linux - mac 装 mutipass 获取 ubuntu

mutipass &#xff1a;https://multipass.run/docs/mac-tutorial mutipass list mutipass launch --name myname mutipass shell myname 获取 root权限&#xff1a; sudo su

Lesson1--数据结构前言

1. 什么是数据结构&#xff1f; 2. 什么是算法&#xff1f; 3. 数据结构和算法的重要性 4. 如何学好数据结构和算法 5. 数据结构和算法书籍及资料推荐 1. 什么是数据结构&#xff1f; 数据结构(Data Structure) 是计算机存储、组织数据的方式&#xff0c;指相互之间存在一…

UWB 雷达动目标检测

1. 静态载波滤除 1. 首先对所有接收脉冲求平均得出参考接收脉冲 [Cir数据为二维数组64*n&#xff0c; 其中n为慢时间域采样的数据帧数] 2. 接着利用每一束接收脉冲减去参考接收脉冲就可以得到目标回波信号&#xff0c;参考接收脉冲的表达式为 2. RD 谱 对雷达回波做静态载波滤…

局域网配置共享文件夹,开机自动共享

设置文件夹共享 选择文件夹&#xff1a;首先&#xff0c;确定你想要共享的文件夹。共享文件夹&#xff1a;右键点击文件夹&#xff0c;选择“属性”&#xff0c;然后切换到“共享”标签页。点击“高级共享”&#xff0c;勾选“共享此文件夹”&#xff0c;并设置共享名称。 配置…

基于yolov9来训练人脸检测

YOLOv9是一个在目标检测领域内具有突破性进展的深度学习模型&#xff0c;尤其以其在实时性与准确性上的优秀表现而受到广泛关注。针对人脸检测这一特定任务&#xff0c;YOLOv9通过其架构创新和算法优化提供了强大的支持。 YOLOv9在继承了YOLO系列&#xff08;如YOLOv7、YOLOv8&…

大模型系列——解读RAG

上篇大概说了几个优化方向&#xff0c;包括提示词&#xff0c;RAG等。那么RAG到底是什么呢&#xff1f;RAG 是2023年最流行的基于 LLM 的应用系统架构。有许多产品几乎完全建立在 RAG 之上&#xff0c;覆盖了结合网络搜索引擎和 LLM 的问答服务&#xff0c;到成千上万个数据聊天…

docker部署在线流程图

下载镜像 docker pull registry.cn-beijing.aliyuncs.com/wuxingge123/drawio:latestdocker-compose部署 vim docker-compose.yml version: 3 services:drawio:container_name: drawioimage: registry.cn-beijing.aliyuncs.com/wuxingge123/drawio:latestports:- 8083:8080v…

【NLP】关于BERT模型的一些认知

BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;模型是由Google在2018年提出的预训练Transformer模型&#xff0c;用于自然语言处理任务。 一. BERT模型的架构 1.1 输入表示 / Encoder模块 BERT中的Encoder模块是由三种Embedding&…

4.7Qt

自由发挥应用场景实现一个登录窗口界面。 mywidget.cpp #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//窗口相关设置this->setWindowTitle("原神启动");this->setWindowIcon(QIcon("C:\\Users\\17212\\Pict…

查遍整个知网都没找到的创新点!基于多目标蜣螂算法的微网/综合能源优化调度程序代码!

前言 随着微电网和分布式新能源的发展&#xff0c;利用动物界觅食或繁殖行为进行寻优的方法受到了人们的关注。多目标蜣螂算法&#xff08;Multi-Objective Cockroach Algorithm&#xff0c;MOCA&#xff09;是一种基于自然界中蜣螂觅食行为的多目标优化算法。它模拟了蜣螂在寻…

一文了解重塑代币发行方式的创新平台 — ZAP

代币的发行方式对加密市场有着重要的影响&#xff0c;它直接影响着项目的社区建设、流动性、价格稳定性以及投资者的参与度&#xff0c;未来预期等&#xff01;合适的发行方式可以吸引更多的投资者和用户参与&#xff0c;提升项目的社区建设和价值实现。不当的发行方式和分配&a…

C++ - 第一节

一.C关键字(C98) C总计63个关键字&#xff0c;C语言32个关键字 asmdoifretuntrycontinueautodoubleinlineshorttypedefforbooldynamic_castintsignedtypeid public break elselongsizeoftypenamethrow caseenummutablestaticunionwchar_tcatchexplicitnamespacestatic_castu…

力扣1379---找出克隆二叉树的相同节点(Java、DFS、简单题)

目录 题目描述&#xff1a; 思路描述&#xff1a; 代码&#xff1a; &#xff08;1&#xff09;&#xff1a; &#xff08;2&#xff09;&#xff1a; 题目描述&#xff1a; 给你两棵二叉树&#xff0c;原始树 original 和克隆树 cloned&#xff0c;以及一个位于原始树 ori…

vue2开发好还是vue3开发好vue3.0开发路线

Vue 2和Vue 3都是流行的前端框架&#xff0c;它们各自有一些特点和优势。选择Vue 2还是Vue 3进行开发&#xff0c;主要取决于你的项目需求、团队的技术栈、以及对新特性的需求等因素。以下是一些关于Vue 2和Vue 3的比较&#xff0c;帮助你做出决策&#xff1a; Vue 2&#xff1…

微信小程序使用自己的布局

我第一天学习微信小程序&#xff0c;照着黑马程序员老师的操作模仿编辑。因为视频是23年的&#xff0c;我24年4月份学习发现很多地方不一样了。 新版微信开发者工具中没有自带wxss文件。我自己建了一个list.wxss文件&#xff0c;发现用不了&#xff0c;在list.wxml文件中编写v…