c++的学习之路:13、vector(2)

news2024/11/16 22:23:50

本章主要是模拟实现vector,文章末附上代码,和源码。

目录

一、STL源码

二、构造与析构

三、迭代器与【】、size、capacity、empty

四、reserve与resize

五、push_back与pop_back

六、insert与erase

七、测试 1

八、代码

九、思维导图


一、STL源码

今天看的是STL30这个源码,他的vector点开是下图这种可以看出他也是调用了几个头文件,上面注释的就是一些开源声明,大概就是说是可以使用、增删查改甚至售卖,做出有用的修改也需要声明。

如下图二可以看出vector的参数是只有三个原生指针,这个就是从图一这里就可以看出是一个typede进行的重定义的。

 他的size,capacity是如下图这样使用的,下面九不一一展示了,源码上传了可以自己看看。

二、构造与析构

如下方代码就是这个构造和析构,这里是放在了我的命名空间中以防和库里面的vector重复,这里是利用了缺省传值,在定义的时候直接赋值为nullptr然后进行一个空的初始化,然后如下方代码中vector(size_t n, const T& val = T())这一句就是利用一个匿名对象进行初始化,因为这样就可以直接使用模板进行构造,因为这样就可以使用不用的类型进行初始化对象,然后又利用了模板参数InputIterator进行初始化,这里就是如上篇文章中可以使用范围进行初始化,这里就是利用迭代器的原理,first就是迭代器的begin,last就是迭代器的end,也就是首和尾,然后进行构造,相当于缺省值的构造,这里面构造是需要开辟空间和插入数据,所以这里先写在这了,代码在后面文章, vector(int n, const T& val = T())有个这个是因为写入的值默认是整形,在构造时会进行隐形类型转换,size_t是无符号整形,需要转化,但是有类模板会优先使用这个就会造成野指针。

namespace ly
{
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;
        typedef const T* const_iterator;

        vector()
        {}

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

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

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

        ~vector()
        {
            delete[] _start;
            _start = _finish = _end_of_storage = nullptr;
        }
    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _end_of_storage = nullptr;
    };

}
 

三、迭代器与【】、size、capacity、empty

如下方代码所示,先看迭代器,在上文中就已经重定义了iterator是T*,所以这里begin就是直接返回start的指针,end就是finish,看过源码和之前模拟实现过string就会发现这里很好用,这里也是同样的有const,因为这里需要重载就是因为需要访问const类型的,size就是finish-start就能得出size,同理capacity就是end_of_storage - start,enpty就是判断是否满了,这里就是start等于finish的时候就是满了,【】就是直接访问就可以了,在pos位置进行访问,这里也是如下方代码所示。

        iterator begin()
        {
            return _start;
        }

        iterator end()
        {
            return _finish;
        }

        const_iterator begin() const
        {
            return _start;
        }

        const_iterator end() const
        {
            return _finish;
        }

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

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

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

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

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

四、reserve与resize

这里是和之前模拟实现string的时候差不多,判断容量是否够,不够减扩容,这里因为需要计算—finish地址,所以提前记录了size,然后创建一个空间,然后利用memcpy进行拷贝数据,在把旧的start释放了,在指向新的空间,在把finish和end_of_storage计算出来就好了,resize也是需要判断是否是缩容,缩容并不需要缩容,只需要删除数据就可以了,扩容也就是需要扩容后,再把数据初始化就可以了。

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

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

五、push_back与pop_back

这里就是先判断是否满了,满了就先进行扩容,然后进行存入数据,没满就把数据直接存入,删除也就是直接--覆盖就好了。

        void push_back(const T& x)
        {
            if (_finish == _end_of_storage)
            {
                reserve(capacity() == 0 ? 4 : capacity() * 2);
            }
            *_finish = x;
            ++_finish;
        }

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

六、insert与erase

如下方代码,这里实现的思路是先断言,pos位置是在start和finish之间,不是就报错,如果刚好数据满了就进行扩容,这里需要注意的是扩容的时候需要进行计算pos的绝对位置,也就是距离start的长度,在扩容后在进行计算pos位置,然后就是挪动数据与把数据存入,erase就不需要判断相等finish的时候,因为满了也可以删,然后在进行挪动覆盖,这个就是erase的实现。

        iterator insert(iterator pos, const T& val)
        {
            assert(pos >= _start);
            assert(pos <= _finish);
            if (_finish == _end_of_storage)
            {
                size_t len = pos - _start;
                reserve(capacity() == 0 ? 4 : capacity() * 2);
                pos = _start + len;
            }
            iterator end = _finish - 1;
            while (end >= pos)
            {
                *(end + 1) = *end;
                --end;
            }
            *pos = val;
            ++_finish;
            return pos;
        }

        void erase(iterator pos)
        {
            assert(pos >= _start);
            assert(pos < _finish);
            iterator start = pos + 1;
            while (start != _finish)
            {
                *(start - 1) = *start;
                ++start;
            }
            --_finish;
        }

七、测试 1

这里就进行测试一下上面写的代码是否有错,如下图的代码就是测试push_back与pop_back的写发,然后这里也是测试了下迭代器的使用,for的实现就是迭代器。

void Print(const vector<int>& v)
    {
        for (auto vi : v)
        {
            cout << vi << ' ';
        }
        cout << endl;
    }

    void Test1()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        v1.push_back(4);
        Print(v1);
        v1.pop_back();
        v1.pop_back();
        Print(v1);
    }

 

 这里就是测试了下【】与利用模板进行范围的初始化

void Test2()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        v1.push_back(4);
        Print(v1);
        vector<int> v2(v1.begin(), v1.end());
        Print(v2);
        for (size_t i = 0; i < v2.size(); i++)
        {
            cout << v2[i] << ' ';
        }
        cout << endl;
    } 

 这里是测试插入和删除,这里利用了find找到1和3进行头插和在3的位置插入,如下方所示。

void Test3()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        v1.push_back(4);
        Print(v1);
        auto pos = find(v1.begin(), v1.end(), 1);
        v1.insert(pos, 0);
        pos = find(v1.begin(), v1.end(), 3);
        v1.insert(pos, 30);
        Print(v1);
        pos = find(v1.begin(), v1.end(), 0);
        v1.erase(pos);
        pos = find(v1.begin(), v1.end(), 30);
        v1.erase(pos);
        Print(v1);
    } 

八、代码

vector.h

#pragma once
#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;

namespace ly
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;

		vector()
		{}

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

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

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

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

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator begin() const
		{
			return _start;
		}

		const_iterator end() const
		{
			return _finish;
		}

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

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

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

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

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

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

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

		void push_back(const T& x)
		{
			if (_finish == _end_of_storage)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}
			*_finish = x;
			++_finish;
		}

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

		iterator insert(iterator pos, const T& val)
		{
			assert(pos >= _start);
			assert(pos <= _finish);
			if (_finish == _end_of_storage)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = val;
			++_finish;
			return pos;
		}

		void erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);
			iterator start = pos + 1;
			while (start != _finish)
			{
				*(start - 1) = *start;
				++start;
			}
			--_finish;
		}

	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _end_of_storage = nullptr;
	};

	void Print(const vector<int>& v)
	{
		for (auto vi : v)
		{
			cout << vi << ' ';
		}
		cout << endl;
	}

	void Test1()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		Print(v1);
		v1.pop_back();
		v1.pop_back();
		Print(v1);
	}

	void Test2()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		Print(v1);
		vector<int> v2(v1.begin(), v1.end());
		Print(v2);
		for (size_t i = 0; i < v2.size(); i++)
		{
			cout << v2[i] << ' ';
		}
		cout << endl;
	}

	void Test3()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		Print(v1);
		auto pos = find(v1.begin(), v1.end(), 1);
		v1.insert(pos, 0);
		pos = find(v1.begin(), v1.end(), 3);
		v1.insert(pos, 30);
		Print(v1);
		pos = find(v1.begin(), v1.end(), 0);
		v1.erase(pos);
		pos = find(v1.begin(), v1.end(), 30);
		v1.erase(pos);
		Print(v1);
	}
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "vector.h"

int main()
{
	ly::Test3();
}

 

九、思维导图

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

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

相关文章

永磁同步电机谐波抑制算法(4)——多同步旋转坐标系谐波电流抑制存在的问题以及改进办法

1.问题的引出 在之前的内容中以及讲了多同步旋转坐标系的五七次谐波电流的抑制。 永磁同步电机谐波抑制算法&#xff08;1&#xff09;——基于多同步旋转坐标系的五七次谐波电流抑制 - 知乎这段时间发现电机里面会存在五次谐波&#xff0c;然后学了学谐波抑制的方法。一般比…

海外公司注册推广:15种利用社交媒体的方法大揭秘-华媒舍

社交媒体在如今的全球化时代扮演着重要的角色&#xff0c;为海外公司注册推广提供了各种有效的方法。本文将介绍15种利用社交媒体的方法&#xff0c;帮助海外公司实现注册推广。 1. 制定战略 在开始利用社交媒体之前&#xff0c;海外公司需要制定一个明确的推广战略。确定目标…

BUUCTF---内涵的软件(reverse)

1.题目描述&#xff0c;下载附件&#xff0c;是一个exe文件 2.用PE查看是否有壳&#xff0c;结果无壳 3.用IDA打开&#xff0c;找到main函数 4.双击_main_0,按f5&#xff0c;页面显示如下 5.看到一串可疑的字符串 6.修改为flag{49d3c93df25caad81232130f3d2ebfad}提交&#xf…

springboot 在fegin调用中sdk集成主工程,A component required a bean of type.....

一 前景描述 1.1 总结 1.主工程启动类&#xff08;这里是FeginApp8081&#xff09;所在的路径&#xff0c;和调用sdk的类&#xff0c;这里是FeginJiekou接口类型&#xff0c;其所在目录和主工程目录启动一致。则不需要在启动加制定扫描注解。 主工程启动类路径&#xff1a;…

MFC扩展库BCGControlBar Pro v34.1 - 支持Windows 10/11字体图标

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v34.1已正式发布了&#xff0c;这个版本包含了对Windows 10/11字体图标的支持、功能区和…

海外仓的出入库流程有什么痛点?位像素海外仓系统怎么提高出入库效率?

随着跨境电商的蓬勃发展&#xff0c;海外仓是其中不可或缺的一个关键环节。而货物的出库与入库则是海外仓管理中的一个核心业务流程&#xff0c;它的运作效率直接影响到整个跨境物流的效率和客户体验。今天&#xff0c;让我们具体来看一看关于海外仓出入库的流程&#xff0c;其…

Linux:谈谈阻塞式和非阻塞式IO

文章目录 阻塞式和非阻塞式IO 本篇总结的核心内容就是非阻塞式IO&#xff0c;直接看代码 阻塞式和非阻塞式IO 阻塞式IO 如下所示是典型的阻塞式IO #include <iostream> #include <unistd.h> using namespace std;int main() {char buff[1024];while(true){ssiz…

DevExpress WinForms中文教程 - 如何通过UI测试自动化增强应用可靠性?(一)

DevExpress WinForm拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜任…

simulink的硬件支持下,串口发送的模型,stm32f407的串口程序调试错误

串口调试助手能接收到数据&#xff0c;为何是8个数据&#xff1f;如之奈何&#xff1f; 参考文章&#xff1a; STM32CubeMxMATLAB Simulink串口输出实验_用stm32cubemx生成的串口都是输出-CSDN博客根据 该文章发送字符串 hello&#xff0c;发送数量为5&#xff0c;接收也是he…

Pytorch张量的数学运算:向量基础运算

文章目录 一、简单运算二、广播运算1.广播的基本规则2.广播操作的例子 三、运算函数 参考&#xff1a;与凤行 张量的数学运算是深度学习和科学计算中的基础。张量可以被视为一个多维数组&#xff0c;其在数学和物理学中有广泛的应用。这些运算包括但不限于加法、减法、乘法、除…

摄影用光这点事儿,摄影光线运用技法

一、资料描述 本套摄影用光资料&#xff0c;大小1.89G&#xff0c;共有60个文件。 二、资料目录 《10日掌握摄影用光》李俊.全彩版.pdf 《DSLR闪光灯摄影完全探索》.pdf 《Light Science and Magic》.pdf 《等待光线》戴维诺顿风光摄影手记.pdf 《高调人像摄影的布光经验…

2024年面试AI编译器岗经验总结

面试经历: 面试中必备的知识: 1.用C++实现一个卷积 (图解)一步一步使用CPP实现深度学习中的卷积 - GiantPandaCVGiantPandaCVhttp://giantpandacv.com/academic/%E7%AE%97%E6%B3%95%E7%A7%91%E6%99%AE/%E5%B0%BD%E8%A7%88%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E…

C语言 循环控制——嵌套循环

目录 循环实现累加累乘 嵌套循环的设计 输出九九乘法表 循环实现累加累乘 嵌套循环的设计 输出九九乘法表

GIt 删除某个特定commit

目的 多次commit&#xff0c;想删掉中间的一个/一些commit 操作方法 一句话说明&#xff1a;利用rebase命令的d表示移除commit的功能&#xff0c;来移除特定的commit # 压缩这3次commit,head~3表示从最近1次commit开始&#xff0c;前3个commit git rebase -i head~3rebase…

Redis 5种数据结构常用命令

文章目录 1 字符串2 哈希3 列表4 集合5 有序集合 1 字符串 命令描述set key value设置指定key的值为valueget key获取指定key的值del key [key …]删除一个或多个keymset key value [key value …]设置多个key的值mget key [key …]获取一个或多个key的值incr key将key中储存的…

考研数学|怎样刷题更有效率?这些坑千万别踩!

考研数学刷题的这些困扰相信大部分的同学都是有的&#xff0c;为此我整理了一些提高考研数学刷题效率的方法和策略&#xff0c;希望能帮助你更有效地学习和解题。 首先要制定合理的刷题计划&#xff0c;首先遵循“教材→视频→全书或辅导讲义→习题集→真题→专项训练→模拟套…

基于SpringBoot的“汽车租赁系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“汽车租赁系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 管理员登录界面图 管理员功能界面…

vue广告悬浮框,页面来回移动,鼠标放上停止,离开移动

1.dom <div class"popup-dialog" id"popupDialog" mouseover"onMmouseover" mouseout"onMouseout"><p>vue广告悬浮</p></div>2.js mounted() {this.initPopup();},beforeDestory() {if (this.times) {clearIn…

k8s CNI Calico 网络模式总结【建议收藏】

目录 calico架构图 ​编辑 IPIP模式下的架构图 calico 核心组件 Overlay 网络模式&#xff1a; Vxlan IPIP IpCrossubnet Pod IP对外暴露 不对外暴露&#xff1a; 实现对外暴露的方法&#xff1a; overlay模式下的网络MTU Iptables & ipvs Full-mesh o…

工程中实践的微服务设计模式

大家好&#xff0c;我是 方圆。最近在读《微服务架构设计模式》&#xff0c;开始的时候我非常的好奇&#xff0c;因为在我印象中&#xff0c;设计模式是常说的那23种设计模式&#xff0c;而微服务的设计模式又是什么呢&#xff1f;这个问题也留给大家&#xff0c;在文末我会附上…