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

【C++】vector容器的模拟实现

目录

一,框架设计

二,构造函数

三,析构函数

四,赋值运算符

五,容器接口的实现

1,迭代器实现

2,“ [] ”运算符的实现

3,swap交换和resize重设大小

4,insert插入和erase删除


介绍:

        本文,我们重点实现vector容器的用法,这里要注意的是vector容器可以接纳任意类型,所以,在实现的时候需使用模板来控制。模拟实现vector重点还要放在构造、析构和赋值运算符重载。


一,框架设计

        vector容器设置中,由于需要接纳各种类型,因此,在框架设计中需要使用模板。除此之外,要想访问未知类型数据,需要使用迭代器来访问。这里,我们设置三个迭代器,分别指向数据块开始位置、有效数据的末尾、存储容量的末尾。

template<class T>
class vector
{
public:
    typedef T* iterator;         
 //数据迭代器
    typedef const T* const_iterator;   //常量迭代器
private:
    iterator _start;                 
// 指向数据块的开始
    iterator _finish;                // 指向有效数据的尾
    iterator _endOfStorage;  // 指向存储容量的尾
};


二,构造函数

        在使用构造函数之前,我们首先要考虑基础的算法设置以方便使用:reverse扩容、capacity容器容量、size容器大小、push_back增添元素、pop_back删除元素。

//获取容器大小

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

//获取容器容量
size_t capacity() const
{
    return _endOfStorage - _start;
}

//容器扩容

void reserve(size_t n)
{
    if (n > capacity())    //只能增容不能缩小
    {
        int newsize = size();
        T* tem = new T[n];
        memcpy(tem, _start, sizeof(T) * newsize);
        if (_start)
        {
            delete[] _start;
        }
        _start = tem;
        _finish = _start + newsize;
        _endOfStorage = _start + n;
    }
}

//增添数据

void push_back(const T& x)
{
    if (capacity() == size())   //这里要注意容量是否够用
    {
        int newcapacity = capacity() == 0 ? 4 : 2 * capacity();
        reserve(newcapacity);
    }
    int newsize = size();
    _start[newsize] = x;
    _finish++;
}

//删除数据

void pop_back()
{
    assert(size() > 0);   //这里要注意容器是否为空
    _finish--;
}

普通构造函数      

        首先,我们先实现无任何传入值的构造函数。这种情况只需初始化容器的各种数据即可,不需要做任何增添。

vector()
{
    _start = _finish = _endOfStorage = nullptr;   //直接将数据设为空
}

        第二种构造方式这里模拟实现构造n个数据,如:vector<int>v(5,8)初始化为5个8。

vector(int n, const T& value = T())
{
    reserve(n);      //这里要先进行扩容
    for (int i = 0; i < n; i++)
    {
        push_back(value);  
    }
}

        第三种构造方式模拟实现迭代器的方式进行构造。因为数据类型未知,所以这里还需要使用模板。

//这里迭代器要使用模板

template<class InputIterator>   

//first指向开始位置,last指向终点的下一位
vector(InputIterator first, InputIterator last)  
{
    int newsize = last - first;  
    reserve(newsize);
    for (int i = 0; i < newsize; i++)
    {
        push_back(*(first + i));
    }
}

拷贝构造函数

        原理跟普通构造函数实现的机制一样,这里就不做过多说明,直接实现代码,如下:

vector(const vector<T>& v)
{
    int newsize = v.capacity();
    reserve(newsize);
    for (int i = 0; i < newsize; i++)
    {
        push_back(v._start[i]);
    }
}


三,析构函数

        析构函数在释放空间之后要记得将数据初始化,以保证安全性。

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


四,赋值运算符

        赋值运算符的实现跟拷贝构造函数实现机制相同。实现拷贝后要返回拷贝后的容器,以便实现连续赋值的情况。

vector<T>& operator= (vector<T> v)
{
    int newsize = v.capacity();
    reserve(newsize);
    for (int i = 0; i < newsize; i++)
    {
        push_back(v._start[i]);
    }
    return *this;
}


五,容器接口的实现

1,迭代器实现

        这里实现begin()、end()、cbegin()、cend()四种常用的迭代器。

//begin()和end()的实现

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

//cbegin()和cend()常量迭代器的实现
const_iterator cbegin() const
{
    const_iterator p = (const_iterator)_start;
    return p;
}
const_iterator cend() const
{
    const_iterator p = (const_iterator)_finish;
    return p;
}

2,“ [] ”运算符的实现

        “ [] ” 运算符实现分为两种,一种是变量的实现,一种是常量const的实现。

//变量实现

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

//常量实现
const T& operator[](size_t pos)const
{
    assert(pos >= 0 && pos < size());
    const T tem = (const T)_start[pos];
    return tem;
}

3,swap交换和resize重设大小

        swap接口实现机制是容器的全部数据实现交换。resize实现时要考虑参数大于容器大小和小于容器大小时的不同情况。

//交换算法

void swap(vector<T>& v)
{
    std::swap(_start, v._start);
    std::swap(_finish, v._finish);
    std::swap(_endOfStorage, v._endOfStorage);
}

//设定大小算法

void resize(size_t n, const T& value = T())
{
    assert(n >= 0);  //防止错误操作
    if (n < size())  //小于容器大小时的情况
    {
        _finish = _start + n;
    }
    else     //大于等于容器大小时的情况
    {
        reserve(n);
        for (int i = 0; i < n - size(); i++)
        {
            push_back(value);
        }
    }
}

4,insert插入和erase删除

        这里实现insert插入要注意的是选择位置时,因为不确定数据类型,因此要在指定迭代器的位置进行插入,最后返回该位置的迭代器。

        erase删除位置与insert插入位置一样,删除迭代器所指向的位置,最后返回该位置的迭代器。

//插入算法,在pos位置下插入数据x

iterator insert(iterator pos, const T& x)
{

    //要考虑指定插入的位置在合理范围之内
    assert(pos >= _start && pos < _finish);
    if (size() == capacity())
    {
        reserve(size() + 1);
    }
    for (iterator it = _finish - 1; it >= pos; it--)
    {
        *(it + 1) = *(it);
    }
    *pos = x;
    return pos;
}

//删除算法,删除pos位置下的数据
iterator erase(iterator pos)
{

    //要考虑指定删除的位置在合理范围之内
    assert(size() > 0);
    assert(pos >= _start && pos < _finish);
    for (iterator i = pos; i < _finish - 1; i++)
    {
        *(i) = *(i + 1);
    }
    _finish--;
    return pos;
}

相关文章:

【C++】vector容器的模拟实现

目录 一&#xff0c;框架设计 二&#xff0c;构造函数 三&#xff0c;析构函数 四&#xff0c;赋值运算符 五&#xff0c;容器接口的实现 1&#xff0c;迭代器实现 2&#xff0c;“ [] ”运算符的实现 3&#xff0c;swap交换和resize重设大小 4&#xff0c;insert插入…...

华为Harmony——ArkTs语言

文章目录 一、简单示例二、声明式UI描述创建组件无参有参数 配置属性配置事件配置子组件 三、自定义组件基本用法基本结构成员函数/变量 一、简单示例 我们以一个具体的示例来说明ArkTS的基本组成。如下图所示&#xff0c;当开发者点击按钮时&#xff0c;文本内容从“Hello Wo…...

uniapp使用colorUI

colorUI 微动画 | ColorUI 使用文档 1&#xff1a;把colorui里三个文件复制到自己项目中去 App.vue </script> <style> import url(colorui/icon.css); import url(colorui/main.css); import url("colorui/animation.css");-webkit-keyframes show {…...

浅谈测试自动化selenium之POM模式

基于本人也是一个初学者&#xff0c;在运用POM模式的时候记录一下自己的学习笔记。 如果你是大神&#xff0c;那么可以略过&#xff0c;如果你是初学者&#xff0c;希望对你有帮助。 本文阐述了以下几个问题&#xff1a; 什么叫POM模式 为什么要用POM模式 POM模式的思想 POM模…...

什么是事件传播、事件冒泡、事件捕获?

一、事件传播 1、概述 &#xff08;1&#xff09;当事件发生在DOM元素上时&#xff0c;该事件并不完全发生在那个元素 &#xff08;2&#xff09;在冒泡阶段中&#xff0c;事件冒泡或向上传播至父级、祖父级、祖父的父级&#xff0c;直到 window 为止 &#xff08;3&#x…...

【uniapp】uniapp中本地存储sqlite数据库保姆级使用教程(附完整代码和注释)

数据库请求接口封装 uniapp中提供了plus.sqlite接口&#xff0c;在这里我们对常用的数据库请求操作进行了二次封装 这里的dbName、dbPath、recordsTable 可以根据你的需求自己命名 module.exports {/** * type {String} 数据库名称*/dbName: salary,/*** 数据库地址* type {…...

微软推出了GPT-RAG:这是一个机器学习库,为在Azure OpenAI上使用RAG模式生产部署大型语言模型(LLMs)提供了企业级参考架构

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

Centos系统升级gcc版本

自己环境的gcc版本太低&#xff0c;影响使用SAN全家桶进行内存泄露检查 当前环境gcc版本查看 gcc --version 进行升级&#xff1a; 1、安装EPEL存储库 yum install epel-release -y 2、确保系统已经更新到最新版本 yum update -y 3、安装GCC编译器及其相关工具包 yum g…...

Http---HTTP响应报文

1. HTTP响应报文分析 HTTP 响应报文效果图: 响应报文说明: --- 响应行/状态行 --- HTTP/1.1 200 OK # HTTP协议版本 状态码 状态描述 --- 响应头 --- Server: Tengine # 服务器名称 Content-Type: text/html; charsetUTF-8 # 内容类型 Transfer-Encoding: chunked # 发送给客…...

iOS 开发设计 App 上架符合要求的截图

1. 真机运行截屏 2. 可以在 Apple developer 官网 Design 下找到 iPhone 边框 https://developer.apple.com/design/resources/ 不用这个边框也行&#xff0c;可以参考已上架 App 的图片框 3. 使用 Procreate&#xff08;PhotoShop&#xff09;创建符合要求的画布大小 4. 导入…...

DRF之引入

目录 一、web应用模式 【1】前后端混合开发 【2】前后端分离 二、API接口 三、接口测试工具&#xff1a;Postman 四、RESTful API规范 【1】什么是RESTful 【2】RESTful API的规范 2.1 数据的安全保障 2.2 接口特征表现 2.3 多数据版本共存 2.4 数据即是资源&#…...

【Skynet 入门实战练习】事件模块 | 批处理模块 | GM 指令 | 模糊搜索

文章目录 前言事件模块批处理模块GM 指令模块模糊搜索最后 前言 本节完善了项目&#xff0c;实现了事件、批处理、模糊搜索模块、GM 指令模块。 事件模块 什么是事件模块&#xff1f;事件模块是用来在各系统之间传递事件消息的。 为什么需要事件模块&#xff1f;主要目的是…...

Web组态可视化编辑器-by组态

演示地址&#xff1a; http://www.by-lot.com http://www.byzt.net web组态可视化编辑器&#xff1a;引领未来可视化编辑的新潮流 随着网络的普及和快速发展&#xff0c;web组态可视化编辑器应运而生&#xff0c;为人们在网络世界中创建和编辑内容提供了更加便捷的操作方式。这…...

PDF.js介绍以及使用

一、PDF.js是什么 PDF.js是一个JavaScript库&#xff0c;可以在现代Web浏览器中渲染和显示PDF文件。它的主要作用是将PDF文件转换为HTML5格式&#xff0c;以便在浏览器上进行展示和交互。 PDF.js的主要功能包括&#xff1a; 在浏览器中显示PDF&#xff1a;PDF.js使用HTML5的…...

经常使用的排序算法

一、直接插入排序 #include <stdio.h>void insert_sort(int arr[], int n){int i, j, tmp;for (i 1; i < n; i){tmp arr[i];j i - 1;while (j > 0 && arr[j] > tmp){ // 将要插入的元素与数组中的元素比较&#xff08;从后向前比&#xff09;arr[j …...

msyql 24day 数据库主从 主从复制 读写分离 master slave 有数据如何增加

目录 环境介绍读写分离纵向扩展横向扩展 数据库主从准备环境主库环境(master)从库配置(slave)状态分析重新配置问题分析 报错解决从库验证 有数据的情况下 去做主从清理环境环境准备数据库中的锁的机制主库配置从库配置最后给主库解锁常见错误 环境介绍 将一个数据库的数据 复…...

使用 Taro 开发鸿蒙原生应用 —— 探秘适配鸿蒙 ArkTS 的工作原理

背景 在上一篇文章中&#xff0c;我们已经了解到华为即将发布的鸿蒙操作系统纯血版本——鸿蒙 Next&#xff0c;以及各个互联网厂商开展鸿蒙应用开发的消息。其中&#xff0c;Taro作为一个重要的前端开发框架&#xff0c;也积极适配鸿蒙的新一代语言框架 —— ArkTS。 本文将…...

Linux下 自定义多线程并发快速压缩解压缩脚本

文章目录 自定义多线程压缩解压缩脚本使用 Linux下 自定义多线程并发快速压缩解压缩脚本 Linux下常用的tar工具无法支持并行 压缩和解压&#xff0c;对于大量小文件的解压缩&#xff0c;可借助pigz工具实现多线程并行工作&#xff0c;实现更为高效的压缩和解压缩。 自定义多线…...

ubuntu20.04下安装pcl_ubuntu安装pcl

pcl点云数据库&#xff0c;用来进行3D信息的获取与处理&#xff0c;和opencv相比较&#xff0c;opencv是用来处理二维信息&#xff0c;他是学术界与工业界针对点云最全的库&#xff0c;且网络上相关的资料很多。以下是pcl的安装步骤以及遇到的问题。 提前说明&#xff0c;本人…...

阿里云常用配置:日志采集、OSS、RAM 权限策略

文章目录 引言I 日志采集1.1 具体查询语法1.2 查询示例1.3 设置token时间(登录过期时间)II OSS2.1 设置防盗链2.2 验证Referer防盗链是否生效III 通义灵码 (智能编码)IV RAM 权限策略4.1 短信策略4.2 内容风险检测引言 SLS I 日志采集...

HalloWing M0开发板:从Arduino到CircuitPython的嵌入式创意实践

1. 项目概述&#xff1a;为什么选择HalloWing M0作为你的创意引擎如果你和我一样&#xff0c;喜欢捣鼓些能发光、发声甚至能感知互动的电子小玩意儿&#xff0c;但又对那些密密麻麻的接线和复杂的底层寄存器配置感到头疼&#xff0c;那么Adafruit HalloWing M0开发板很可能就是…...

STM32CubeMX配置避坑指南:搞定F103C8T6最小系统板的时钟与调试口

STM32CubeMX配置避坑指南&#xff1a;搞定F103C8T6最小系统板的时钟与调试口 当你第一次拿到STM32F103C8T6最小系统板时&#xff0c;CubeMX的图形化配置界面看起来是如此友好。但现实往往比理想骨感——代码下载后毫无反应、调试器连接失败、LED闪烁频率诡异。这些问题十有八九…...

终极指南:如何快速调试LZ4错误日志——结构化错误信息与调试等级详解

终极指南&#xff1a;如何快速调试LZ4错误日志——结构化错误信息与调试等级详解 【免费下载链接】lz4 Extremely Fast Compression algorithm 项目地址: https://gitcode.com/GitHub_Trending/lz/lz4 LZ4作为一款Extremely Fast Compression algorithm&#xff0c;在高…...

Trigger.dev与GitOps集成:自动化工作流任务调度的终极指南

Trigger.dev与GitOps集成&#xff1a;自动化工作流任务调度的终极指南 【免费下载链接】trigger.dev Trigger.dev – build and deploy fully‑managed AI agents and workflows 项目地址: https://gitcode.com/gh_mirrors/tr/trigger.dev 在当今快速发展的软件开发环境…...

Claude Code 模型特定调优与 A/B 测试全解析:Feature Flag、灰度发布、Undercover、安全门控、Prompt 调优与 AI Agent 工程化实战

一、先说结论&#xff1a;AI Agent 真正难的不是“会调用模型”&#xff0c;而是“能持续驾驭模型”很多人做 AI 编码助手、企业智能体、研发提效工具时&#xff0c;第一反应是接入一个更强的大模型&#xff1a;换成更大的参数、更新的版本、更长的上下文&#xff0c;似乎问题就…...

避开这些坑!RT-Thread+lwip网卡驱动开发中的5个常见误区与实战解法

RT-Thread与lwIP网卡驱动开发中的五大性能陷阱与实战突围 在嵌入式网络开发领域&#xff0c;RT-Thread与lwIP的组合已经成为许多开发者的首选方案。然而&#xff0c;这套看似成熟的网络协议栈背后&#xff0c;却隐藏着诸多性能陷阱。本文将揭示五个最常见的开发误区&#xff0c…...

AI大模型产品经理零基础到进阶学习路线图,AI产品经理:不只是懂算法,更需AI思维!

AI产品经理区别于普通产品经理的地方&#xff0c;不止在懂得AI算法&#xff0c;更重要的是具有AI思维。 人工智能产品设计要以操作极度简单为标准&#xff0c;但是前端的简单代表后端的复杂&#xff0c;系统越复杂&#xff0c;才能越智能。 同样&#xff0c;人工智能的发展依赖…...

Zotero插件市场:一站式管理插件的终极解决方案

Zotero插件市场&#xff1a;一站式管理插件的终极解决方案 【免费下载链接】zotero-addons Zotero Add-on Market | Zotero插件市场 | Browsing, installing, and reviewing plugins within Zotero 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-addons 还在为Zo…...

LaTeX2Word-Equation终极指南:打破数学公式编辑的次元壁

LaTeX2Word-Equation终极指南&#xff1a;打破数学公式编辑的次元壁 【免费下载链接】LaTeX2Word-Equation Copy LaTeX Equations as Word Equations, a Chrome Extension 项目地址: https://gitcode.com/gh_mirrors/la/LaTeX2Word-Equation 在学术写作和技术文档创作的…...

PROFINET工业以太网:实时通信与设备互操作性解析

1. PROFINET技术架构解析PROFINET作为工业自动化领域的实时以太网标准&#xff0c;其核心价值在于解决了传统以太网在工业场景中的三大痛点&#xff1a;确定性延迟、实时性保障和设备互操作性。与普通办公以太网不同&#xff0c;工业环境要求通信系统必须满足严格的时序要求&am…...