STL库 —— vector 的编写

news2025/2/9 4:58:14

一、成员变量

二、容量成员

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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MIT6.828 Lab1 Xv6 and Unix utilities

2023MIT6.828 lab-1 官方地址 一、sleep 实验内容 调用sleep&#xff08;系统调用&#xff09;编写用户级别程序能暂停特定时常的系统滴答程序保存在user/sleep.c 实验过程 xv6的参数传递 查看官方文档提示的文件中&#xff0c;多采用如下定义&#xff1a; int main(in…

如何在nuxt中优雅使用swiper,实现过渡反向+贴合无缝+循环播放【核心代码分析】

视频效果 20240402-1723 图片效果 技术栈 Nuxt3 + Swiper11 Nuxt3 Nuxt: The Intuitive Vue Framework Nuxt Swiper11 Swiper - The Most Modern Mobile Touch Slider (swiperjs.com) 当然你也可以是使用nuxt-swiper Nuxt-Swiper GitHub - cpreston321/nuxt-swiper: Swi…

CPU+GPU+NPU三位一体AI边缘控制器,三屏异显,搭载RK3588处理器

XMS-201采用了Rockchip RK3588八核64位处理器&#xff0c;集成ARM Mali-G610 MP4四核GPU&#xff0c;内置AI加速器NPU&#xff0c;可提供6Tops算力&#xff0c;支持主流的深度学习框架&#xff1b;性能强劲的RK3588可为各类AI应用场景带来更强大的性能表现&#xff0c;适用于机…

【40分钟速成智能风控1】互联网金融风险管理简介

目录 瓦联网金融的发展和现状 风险管理类型划分 欺诈风险 第一方和第三方 账户级和交易级 个人和团伙 互联网金融是传统金融业务与新兴互联网技术结合的一个交叉领域&#xff0c;例如互联网公司开展的金融业务&#xff0c;或者金融机构的线上化服务&#xff0c;都属于互联…

Brain.js 的力量:构建多样化的人工智能应用程序

机器学习&#xff08;ML&#xff09;是人工智能 (AI) 的一种形式&#xff0c;旨在构建可以从处理的数据中学习或使用数据更好地执行的系统。人工智能是模仿人类智能的系统或机器的总称。 机器学习&#xff08;ML&#xff09;与复杂的数学纠缠在一起&#xff0c;让大多数初学者…

08 | Swoole 源码分析之 Timer 定时器模块

原文首发链接&#xff1a;Swoole 源码分析之 Timer 定时器模块 大家好&#xff0c;我是码农先森。 引言 Swoole 中的毫秒精度的定时器。底层基于 epoll_wait 和 setitimer 实现&#xff0c;数据结构使用最小堆&#xff0c;可支持添加大量定时器。 在同步 IO 进程中使用 seti…

three.js能实现啥效果?看过来,这里都是它的菜(01)

经常有老铁问我&#xff0c;这里炫酷效果是如何实现的&#xff0c;还有问我想实现什么效果怎么办&#xff0c;甚至还有想实现动态效果&#xff0c;但是描述不出来的。 好吧&#xff0c;统统满足老铁们呢&#xff0c;本期开始分享three.js效果图&#xff0c;并附带简要简介&…

usbserial驱动流程解析_Part2_初始化流程_以probe为例(echo cat测试回环打印不停问题解决)

usb转串口设备需要注册usb侧和serial侧两侧的操作&#xff0c;本文将简要分析二者的初始化流程以及一些关键函数的初始化流程。 module_init(usb_serial_init); tty设备初始化 内核会直接调用usb_serial_init&#xff0c;开始进行usb和serial的初始化&#xff0c;首先是进行t…

全面探究 LangChain Text Splitters

全面探究 LangChain Text Splitters 0. 引言1. 文本拆分器的类型2. 探究各个文本拆分器2-1. Split by HTML header2-2. Split by HTML section2-3. Split by character2-4. Split code2-5. MarkdownHeaderTextSplitter2-6. Recursively split JSON2-7. Recursively split by ch…

lv17 CGI移植 5-1

简介 CGIC是一个支持CGI开发的开放源码的标准C库&#xff0c;可以免费使用&#xff0c;只需要在开发的站点和程序文档中有个公开声明即可&#xff0c;表明程序使用了CGIC库&#xff0c;用户也可以购买商业授权而无需公开声明。 CGIC能够提供以下功能&#xff1a; 分析数据&a…

疲劳驾驶预警系统项目知识点整理

参考&#xff1a; 重磅&#xff01;头部姿态估计「原理详解 实战代码」来啦&#xff01;-阿里云开发者社区 (aliyun.com) Dlib模型之驾驶员疲劳检测三&#xff08;瞌睡点头&#xff09;_疲劳检测 点头-CSDN博客 python毕业设计 深度学习疲劳检测 驾驶行为检测 - opencv cnn…

面试:HashMap

目录 1、底层数据结构&#xff0c;1.7 与1.8有何不同? 2、为何要用红黑树&#xff0c;为何一上来不树化&#xff0c;树化阈值为何是8&#xff0c;何时会树化&#xff0c;何时会退化为链表? 3、索引如何计算? hashCode都有了&#xff0c;为何还要提供hash()方法?数组容量为…

交换机与队列的简介

1.流程 首先先介绍一个简单的一个消息推送到接收的流程&#xff0c;提供一个简单的图 黄色的圈圈就是我们的消息推送服务&#xff0c;将消息推送到 中间方框里面也就是 rabbitMq的服务器&#xff0c;然后经过服务器里面的交换机、队列等各种关系&#xff08;后面会详细讲&…

保研复习数据结构-图(10)

一.图的定义和基本术语 1.什么是图&#xff1f; 图(Graph)是由顶点的有穷非空集合V(G)和顶点之间边的集合E(G)组成&#xff0c;通常表示为:G(V,E)&#xff0c;其中&#xff0c;G表示图&#xff0c;V是图G中顶点的集合&#xff0c;E是图G中边的集合。 2.什么是完全图&#xf…

【第十二篇】使用BurpSuite实现CSRF(实战案例)

CSRF存在前提:简单的身份验证只能保证请求是发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的 业务场景:新增、删除、收藏、编辑、保存使用Burp发现CSRF漏洞的过程如下。 1、如图,存在修改邮箱的功能点如下: 2、修改邮箱的流量包,此时邮箱已被修改: 思路:是…

12、最小覆盖子串

如何想到这个解法 问题的特点&#xff1a; 首先&#xff0c;认识到这是一个关于子串的问题&#xff0c;而且需要考虑子串的最小长度。这提示我们可能需要使用一种方式来逐步探索不同的子串。滑动窗口的适用性&#xff1a;滑动窗口是处理子串问题的常用技巧&#xff0c;特别是当…

X年后,ChatGPT会替代底层程序员吗?

能不能替代&#xff0c;真的很难说&#xff0c;因为机器换掉人&#xff0c;这其实是一个伦理问题。 其实说白了&#xff0c;任何行业在未来都会被AI或多或少的冲击到&#xff0c;因为ChatGPT做为一个可以持续提升智能的AI&#xff0c;在某些方面的智能程度超过人类并不是什么难…

笛卡尔树[天梯赛二叉树专项训练]

文章目录 题目描述思路AC代码 题目描述 输入样例1 6 8 27 5 1 9 40 -1 -1 10 20 0 3 12 21 -1 4 15 22 -1 -1 5 35 -1 -1 输出样例1 YES 输入样例2 6 8 27 5 1 9 40 -1 -1 10 20 0 3 12 11 -1 4 15 22 -1 -1 50 35 -1 -1 输出样例2 NO思路 见注释 AC代码 #include <bits/st…

5. 4 二重循环将二维数组的某列、某矩形转大写

5. 4 二重循环将二维数组的某列、某矩形转大写 1. 把每一行的b都变成大写 assume cs:codesg,ds:data,ss:stack data segmeNTstr db aaaaabbbbbcccccdb aaaaabbbbbcccccdb aaaaabbbbbcccccdb aaaaabbbbbccccc,$ data endsstack segmentdb 10 dup(0) stack endscodesg SEgments…

【Vue】Vue3中的OptionsAPI与CompositionAPI

文章目录 OptionsAPICompositionAPI对比总结 OptionsAPI 中文名:选项式API通过定义methods,computed,watch,data等属性方法&#xff0c;处理页面逻辑。以下是OptionsAPI代码结构 实例代码: <script lang"ts">// js或者tsimport { defineComponent } from vu…