从零开始手写STL库:Vector

news2024/11/24 5:51:27

从零开始手写STL库–Vector部分


文章目录

  • 从零开始手写STL库--Vector部分
  • Vector是什么
  • Vector需要包含什么函数
      • 1)基础成员函数
      • 2)核心功能
  • 基础成员函数的编写
  • 核心功能函数的编写
  • 总结


Vector是什么

std::vector 是一个动态数组,它在内存中以连续的块存储元素。与静态数组相比,std::vector 允许在运行时动态调整大小,而无需手动管理内存。

Vector需要包含什么函数

应当具有:

1)基础成员函数

构造函数:初始化Vector
析构函数:释放内存,当运行结束后要摧毁这个Vector防止内存泄漏
拷贝构造函数:允许用已有的Vector创建新的Vector
拷贝赋值操作符:允许多个Vector相互赋值

2)核心功能

push_back:在vector末尾加入元素
size:获取vector的长度
get:访问vector某处的元素
pop_back:移除vector末尾的元素
insert:在vector某处插入元素
clear:清空vector

基础成员函数的编写

Vector的成员:
一个Vector应当有指向它的指针、Vector的容量和Vector目前的长度,这样才能方便调用,以及判断是否需要扩充

template <typename T>
class myVector
{
private:
    T * elements;
    size_t capacity;
    size_t current_size;
};

那么构造函数和析构函数也就出来了,为以上三个元素赋初值,运行结束时释放elements即可

public:
    myVector() : elements(nullptr), capacity(0), current_size(0){}
    ~myVector()
    {
        delete[] elements;
    }

那么拷贝构造函数是不是就是:

myVector(const myVector & other) : 
	elements(other.elements), capacity(other.capacity), current_size(other.current_size)

那就错了,这里elements并不是真实的数组,而是数组的指针,如果这么做的话,对other的操作会影响这里
所以这里elements需要额外创造一个数组来复制它,数据一样,指针不同

myVector(const myVector & other) : capacity(other.capacity), current_size(other.current_size)
{
    elements = new T[capacity];                                                 // copy arrays of the same length 
    std::copy(other.elements, other.elements + current_size, elements);         // fill the array and finish copying
}

拷贝赋值操作符和拷贝构造函数很像,但是要先释放当前的elements指针,防止内存泄漏

    myVector &operator = (const myVector & other)
    {
        if(this != other)
        {
            delete[] elements;
            capacity = other.capacity;
            current_size = other.current_size;
            elements = new T[other.capacity];
            std::copy(other.elements, other.elements + current_size, elements);
        }
        return *this;
    }

这里不能直接调用析构函数和拷贝构造函数,因为析构函数和拷贝构造函数的调用不会像普通函数那样直接调用,而是通过对象的生命周期管理机制自动调用

核心功能函数的编写

1、push back函数:将元素加入到vector的末尾
试想这样一个流程:初始化vector->push_back,此时vector的数组大小还是0,根本没法push进去
所以先写一个分配内存的函数

    void reserve(size_t newCapacity)
    {
        if (newCapacity > capacity)
        {
            T *newElements = new T[newCapacity];
            std::copy(elements, elements + current_size, newElements);
            delete[] elements;
            elements = newElements;
            capacity = newCapacity;
        }
    }

这样就可以在push前检查一下是否有余量,无余量了就扩充数组内容

    void push_back(const T & input)
    {
        if(current_size == capacity)
        {
            capacity ? reserve(2 * capacity) : reserve(1);
        }
        elements[current_size++] = input;
    }

2、size函数:获取当前vector长度

    size_t size()
    {
        return current_size;
    }

3、get函数:访问vector某处的元素
这里模仿c++库中的vector,希望实现的是通过vector[index]来获取index处的元素

    T & operator[](size_t index)
    {
        if(index >= current_size) std::cout << "Index overstep" << std::endl;
        return elements[index];
    }
    const T & operator[](size_t index) const
    {
        if(index >= current_size) std::cout << "Index overstep" << std::endl;
        return elements[index];
    }

这里区分const和non-const是为了防止以下问题的出现:当vector本身有const时,操作符也要有const属性
在这里插入图片描述
4、pop back函数:移除vector末尾的元素

    void pop_back()
    {   
        if(current_size) current_size--;
    }

5、insert函数:在vector某处插入元素
这里要考虑两种情况:
一是index超出了数组范围,那么要说越界
二是index没超出范围,但是数组已经满了怎么办
三就是正常的后移index后面的元素,再插入index

    void insert(const size_t index, const T & input)
    {
        if(index > current_size) throw std::out_of_range("Index overstep");
        if(current_size == capacity) reserve(capacity == 0 ? 1 : 2 * capacity);
        for(size_t i = current_size; i > index; i --)
        {
            elements[i] = elements[i - 1];
        } 
        elements[index] = input;
        current_size ++;
    }

6、clear函数:清空vector

    void clear()
    {
        current_size = 0;
    }

7、其他函数
在使用for(auto ele : myVector)时发现出现错误:此基于范围的for语句需要合适的begin函数,但未找到
所以还需要在class中定义这些信息

    T* begin()
    {
        return elements;
    }

    T* end()
    {
        return elements + current_size;
    }

    const T* begin() const
    {
        return elements;
    }

    const T* end() const
    {
        return elements + current_size;
    }

完整的代码在:Github 中,编译建议在Linux系统中,因为本人是在Ubuntu18中编写的

理论上Windows也可以运行

总结

Vector简单实现并不算难,代码也不复杂,但是真要和C++的STL正经实现相比,还是差非常多的,写下来是为了理解vector在处理数组长度不足时怎么申请内存以及释放内存

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

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

相关文章

安装Nginx以及简单使用 —— windows系统

一、背景 Nginx是一个很强大的高性能Web和反向代理服务&#xff0c;也是一种轻量级的Web服务器&#xff0c;可以作为独立的服务器部署网站&#xff0c;应用非常广泛&#xff0c;特别是现在前后端分离的情况下。而在开发过程中&#xff0c;我们常常需要在window系统下使用Nginx作…

SwiftUI中List的liststyle样式及使用详解添加、移动、删除、自定义滑动

SwiftUI中的List可是个好东西&#xff0c;它用于显示可滚动列表的视图容器&#xff0c;类似于UITableView。在List中可以显示静态或动态的数据&#xff0c;并支持垂直滚动。List是一个数据驱动的视图&#xff0c;当数据发生变化时&#xff0c;列表会自动更新。针对List&#xf…

关于下载obsidian SimpRead Sync中报错的问题

参考Kenshin的配置方法&#xff0c;我却在输入简悦的配置文件目录时多次报错。 bug如下&#xff1a; 我发现导出来的配置文件格式如下&#xff1a; 然后根据报错的bug对此文件名进行修改&#xff0c;如下&#xff1a; 解决。

【后端面试题】【中间件】【NoSQL】MongoDB查询优化2(优化排序、mongos优化)

优化排序 在MongoDB里面&#xff0c;如果能够利用索引来排序的话&#xff0c;直接按照索引顺序加载数据就可以了。如果不能利用索引来排序的话&#xff0c;就必须在加载了数据之后&#xff0c;再次进行排序&#xff0c;也就是进行内存排序。 可想而知&#xff0c;如果内存排序…

elasticsearch-users和elasticsearch-reset-password介绍

elasticsearch 内置 elastic, kibana, logstash_system,beats_system 共4个用户&#xff0c;用途如下&#xff1a; elastic 账号&#xff1a;内置的超级用户&#xff0c;拥有 superuser 角色。 kibana 账号&#xff1a;用来连接 elasticsearch 并与之通信。Kibana 服务器以该用…

ACL2023 | 如何用175条种子数据打造顶级指令模型?揭秘self-instruct:媲美InstructGPT001的秘密武器

1. 论文的核心问题和核心贡献 核心问题&#xff1a;该论文解决的问题是大规模语言模型在微调响应指令时过于依赖人工编写的指令数据&#xff0c;这些数据往往在数量、种类和创意上都存在局限&#xff0c;阻碍了模型的广泛泛化能力。研究的主要目标是开发一种方法&#xff0c;通…

Java实习手册(小白也看得懂)

秃狼说 距离俺发布的学习路线已经六个月了&#xff0c;那我给小伙伴的学习周期是四五个月左右&#xff0c;我相信大多的小伙伴已经学习的差不多了。正好赶上暑期实习的阶段&#xff0c;在暑期找到实习就成为暑期的头等大事。 实习经验在校招的起到决定性的作用&#xff0c;所…

代码随想录算法训练营第九天|151.翻转字符串里的单词、右旋字符串、28. 实现 strStr()、459.重复的子字符串

打卡Day9 1.151.翻转字符串里的单词2.右旋字符串3.28. 实现 strStr()4.459.重复的子字符串 1.151.翻转字符串里的单词 题目链接&#xff1a;翻转字符串里的单词 文档讲解&#xff1a; 代码随想录 思路&#xff1a;首先&#xff0c;移除多余的空格&#xff1b;然后&#xff0c…

Amesim应用篇-信号传递

前言 在Amesim中常见的信号传递是通过信号线连接&#xff0c;针对简单的模型通过信号线连接还可以是信号线清晰规整&#xff0c;方便查看。如果模型较复杂&#xff0c;传递信号的元件较多时&#xff0c;此时再继续使用信号线进行信号传递&#xff0c;可能会使草图界面看起来杂…

比赛获奖的武林秘籍:02 国奖秘籍-大学生电子计算机类竞赛快速上手的流程,小白必看

比赛获奖的武林秘籍&#xff1a;02 国奖秘籍-大学生电子计算机类竞赛快速上手的流程&#xff0c;小白必看 摘要 本文主要介绍了大学生参加电子计算机类比赛&#xff08;电赛、光电设计大赛、计算机设计大赛、嵌入式芯片与系统设计大赛等比赛&#xff09;的流程和涉及到的知识…

一本超简单能用Python实现办公自动化的神书!让我轻松摆脱办公烦恼!

《超简单&#xff1a;用Python让Excel飞起来》 这本书旨在通过Python与Excel的“强强联手”&#xff0c;为办公人员提供一套高效的数据处理方案。书中还介绍了如何在Excel中调用Python代码&#xff0c;进一步拓宽了办公自动化的应用范围。 全书共9章。第1~3章主要讲解Python编…

软件设计之Java入门视频(11)

软件设计之Java入门视频(11) 视频教程来自B站尚硅谷&#xff1a; 尚硅谷Java入门视频教程&#xff0c;宋红康java基础视频 相关文件资料&#xff08;百度网盘&#xff09; 提取密码&#xff1a;8op3 idea 下载可以关注 软件管家 公众号 学习内容&#xff1a; 该视频共分为1-7…

【C++】 解决 C++ 语言报错:Memory Leak

文章目录 引言 内存泄漏&#xff08;Memory Leak&#xff09;是 C 编程中常见且严重的内存管理问题之一。当程序分配了内存而没有正确释放&#xff0c;导致内存无法被重新利用时&#xff0c;就会发生内存泄漏。这种错误会导致程序占用越来越多的内存&#xff0c;最终可能导致系…

Using a text embedding model locally with semantic kernel

题意&#xff1a;在本地使用带有语义核&#xff08;Semantic Kernel&#xff09;的文本嵌入模型 问题背景&#xff1a; Ive been reading Stephen Toubs blog post about building a simple console-based .NET chat application from the ground up with semantic-kernel. Im…

C++基础21 二维数组及相关问题详解

这是《C算法宝典》C基础篇的第21节文章啦~ 如果你之前没有太多C基础&#xff0c;请点击&#x1f449;C基础&#xff0c;如果你C语法基础已经炉火纯青&#xff0c;则可以进阶算法&#x1f449;专栏&#xff1a;算法知识和数据结构&#x1f449;专栏&#xff1a;数据结构啦 ​ 目…

【MindSpore学习打卡】应用实践-计算机视觉-深入解析 Vision Transformer(ViT):从原理到实践

在近年来的深度学习领域&#xff0c;Transformer模型凭借其在自然语言处理&#xff08;NLP&#xff09;中的卓越表现&#xff0c;迅速成为研究热点。尤其是基于自注意力&#xff08;Self-Attention&#xff09;机制的模型&#xff0c;更是推动了NLP的飞速发展。然而&#xff0c…

嵌入式UI开发-lvgl+wsl2+vscode系列:6、布局(Layouts)

一、前言 这节总结一下整体页面的布局方式&#xff0c;lvgl的布局方式比较少&#xff0c;目前只有flex和grid两大类布局&#xff0c;即弹性布局和网格布局&#xff0c;弹性布局一般就是指定相对位置&#xff0c;网格布局就是将整个页面划分为网格状&#xff0c;我们做其它的UI…

【Python机器学习】处理文本数据——用tf-idf缩放数据

为了按照我们预计的特征信息量大小来缩放特征&#xff0c;而不是舍弃那些认为不重要的特征&#xff0c;最常见的一种做法就是使用词频-逆向文档频率&#xff08;tf-idf&#xff09;。这一方法对某个特定文档中经常出现的术语给与很高的权重&#xff0c;但是堆在语料库的许多文档…

pandas,dataframe使用笔记

目录 新建一个dataframe不带列名带列名 dataframe添加一行内容查看dataframe某列的数据类型新建dataframe时设置了列名&#xff0c;则数据类型为object dataframe的保存保存为csv文件保存为excel文件 dataframe属于pandas 新建一个dataframe 不带列名 df pd.DataFrame() 带…

【Linux开发】基于ALSA库实现音量调节

基于ALSA库实现音量调节 ALSA库实现音量调节1、使用alsamixer工具查看音频接口2、完整代码2.1、snd_mixer_open2.2、snd_mixer_attach、2.3、snd_mixer_selem_register2.4、snd_mixer_load2.5、snd_mixer_first_elem/snd_mixer_elem_next2.6、snd_mixer_selem_get_playback_vol…