【C++技能树】Vector类解析与模拟实现

img

Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法…感兴趣就关注我bua!

Vector

  • 0.Vector简介
  • 1.Vector常用接口
    • 1.1constructor构造函数
    • 1.2 iterator
    • sort与find
      • find
      • sort
    • 1.3 Capacity相关接口
    • 1.4 Modify相关接口
  • 2. Vector模拟实现
    • 2.1 构造函数
      • 2.1.1无默认参数构造函数
      • 2.1.2 带参数默认构造函数
    • 2.2析构函数
    • 2.3 迭代器
    • 2.4 Capacity相关接口
    • 2.5 swap()
    • 2.6operator =
    • 2.7 push_back()
    • 2.8 insert()
    • 2.9 erase()
    • 2.10 pop_back()
    • 2.11 opeartor []
    • 2.11 opeartor []

img

0.Vector简介

Vector是一个动态数组的容器,可以容纳各种类型的序列容器。称其为数组,意味着:**其也可以用下标去访问,类似与之前的顺序表。**所以,Vector分配空间的时候也不是说用多少就分配多少,会多分配一些,因为向系统申请空间这个成本是相对较大的。

1.Vector常用接口

因为String之前已经详细解读了各个接口,在标准STL中,各个接口的传入参数,返回值都大多相同。所以在这一篇章不重点讲解接口。遗忘的uu们可以去看看这篇文章 [String解析]((45条消息) 【C++技能树】String类解析与模拟实现_ppeua的博客-CSDN博客)

vector的声明方式,其中T为模板

vector<T>v;

1.1constructor构造函数

(constructor)构造函数声明接口说明
vector()无参构造
vector(size_type n, const value_type& val = value_type())构造并初始化n个va
vector (const vector& x);拷贝构造
vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造

直接上代码来看看Vector构造函数的使用

  1. 默认构造函数:
vector (const allocator_type& alloc = allocator_type());

其中 const allocator_type& alloc = allocator_type()是指用来创建一个自定义的分配器来实现特殊的内存管理行为,如对齐、缓存池等.在初学C++的阶段我们只需要使用默认内存分配策略即可.

所以其默认构造函数使用为

vector<T>v;
vector<int>v;
  1. 填充构造函数:

    vector (size_type n, const value_type& val = value_type(),const allocator_type& alloc = allocator_type());
    

    往容器中填充n个val

    vector<int>v(5,1);
    
  2. 使用迭代器构造函数:

template <class InputIterator>vector (InputIterator first, InputIterator last,const allocator_type& alloc = allocator_type());
vector<int>v(5,3);
vector<int>v1(v.begin(),v.end());

首先,先使用填充构造,往v里填充5个3.之后使用迭代器构造函数,begin()–end()这个范围里的内容都放到v1中.

  1. 拷贝构造函数:
vector (const vector& x);

1.2 iterator

iterator的使用接口说明
begin()+end()获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置 的iterator/const_iterator
rbegin()+rend()获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的 reverse_iterator

**这是[begin(),end()]与[rbegin(),rend()]的结构图:**任何使用迭代器的场景中,其都是[begin(),end())左闭右开的模式(也就是可以取到左边,但取不到右边)

sort与find

这两个函数是 algorithm中给出的函数.

find

InputIterator find (InputIterator first, InputIterator last, const T& val);

在指定区间中寻找val,找到之后返回其iterator,其实现如下,通过遍历区间去寻找val

template<class InputIterator, class T>InputIterator find (InputIterator first, InputIterator last, const T& val)
{while (first!=last) {if (*first==val) return first;++first;}return last;
}
vector<int>v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
cout<<*find(v.begin(),v.end(),3);

输出结果为:3

sort

 void sort (RandomAccessIterator first, RandomAccessIterator last);

将指定区间中的数据进行排序.默认使用 < 进行排序 (相同元素不保证是稳定排序.也就是会改变原始数据的位置)

vector<int>v;
v.push_back(4);
v.push_back(1);
v.push_back(3);
v.push_back(2);
sort(v.rbegin(),v.rend());
for(auto s:v)cout<<s;

使用逆向迭代器,进行从大到小的排序.

输出结果为:4321

1.3 Capacity相关接口

容量空间接口说明
size返回数据个数
capacity返回当前占用空间大小
empty返回是否为空
resize改变size
reserve改变capacity

和string都相同,这里 就不过多赘述

1.4 Modify相关接口

Modify接口说明
push_back尾插
pop_back尾删
insert插入
erase删除
swap交换两个vector空间
operator[]像数组一样访问

这里需要重点讲解下erase与insert,他们的作用其是通过当前迭代器的位置插入或删除一个元素.

但是如果直接使用之前的迭代器,可能会出现迭代器失效的问题:本质原因就是访问了已经不属于自己的迭代器

vector底层原理旧空间被释放掉, 而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的 空间,而引起代码运行时崩溃。 解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新 赋值即可。

2. Vector模拟实现

Vector和String类似,也有三个私有属性,用来表示存储空间的范围(STL源码可能实现不一样 但思想是这样).

并先声明迭代器(可以简单的看为类型指针)

在这里插入图片描述

typedef T* iterator;
typedef const T* const_iterator;
private:_start;_finish;_endofstorage;

2.1 构造函数

2.1.1无默认参数构造函数

vector():_start(nullptr),_finish(nullptr),_endofstorage(nullptr)
{}

这是最初版的构造函数,需要用到初始化列表对其进行构造.但是在C++11后打了补丁后,可以在私有属性的时候就给其默认参数.

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

此时的默认构造函数就可以什么都不需要写了.

vector():
{}

2.1.2 带参数默认构造函数

  1. 填充形构造函数:

    vector(size_t n, const T& val = T())
    {resize(n, val);
    }
    vector(int n, const T& val = T())
    {resize(n, val);
    }
    template<class InputIterator>
    vector(InputIterator begin, InputIterator end)
    {while (begin != end){push_back(*begin);begin++;}
    }
    

    第二个形式参数给了一个默认参数,在C++中每一个类型都可以看成一个类,此时其默认构造函数就是类名(),例如

    int(),double(),string()…

    第一种和第二种本质是在完成同一个事情,但是由于有了迭代器的加入。当你使用如下构造方案时

    vector<int>v(1,5);
    

    我们给的构造参数是两个相同的类型,我们本意是想让他走第一种进行初始化构造,但因为类型相同,往往会被识别成第三种,使用迭代器进行初始化.

    所以我们需要对int进行单独处理,所以有了第二种.

  2. 使用vector类型进行构造:

    vector(const vector<T>& v)
    {_start = new T[v.capacity()];for (size_t i = 0; i < v.size(); i++){_start[i] = v._start[i];}//_finish = v._finish; 只是令地址相等_finish = _start + v.size();_endofstorage = _start + v.capacity();
    }
    

    在类的成员函数中可以直接访问类的私有成员变量,

    这里不能使用memcpy:因为memcpy是对内存进行拷贝,若是内置类型则可以完成任务.但为自定义类型,则会变成浅拷贝,所以需要调用=进行重载完成拷贝
    在这里插入图片描述

    整体思路为:先给start分配一段新的空间,然后依次将形参中的东西拷贝过来,最后计算长度与空间大小.(注意这里finish是地址不能直接赋值)

2.2析构函数

要把申请的空间全部还给系统.

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

2.3 迭代器

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

2.4 Capacity相关接口

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

resize():

 void resize(size_t n, const T& val){if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish != _start + n){*_finish = val;_finish++;}}}
 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;_endofstorage = _start + n;}}

这里与string类差不多就不过多解释了.

2.5 swap()

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

2.6operator =

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

2.7 push_back()

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

2.8 insert()

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

2.9 erase()

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

2.10 pop_back()

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

2.11 opeartor []

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

pos < _finish&& pos >= _start);
iterator it = pos + 1;
while (it != _finish)
{
*(it - 1) = *it;
it++;
}
_finish;
return pos;
}


## 2.10 pop_back()~~~cpp
void pop_back()
{erase(--end());
}

2.11 opeartor []

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

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

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

相关文章

linux:secureCRT通过pem证书远程访问服务器

参考&#xff1a; secureCRT通过pem证书远程访问服务器_Fengshana的博客-CSDN博客 总结&#xff1a; 配置公钥即可

前端vue uni-app仿美团下拉框下拉筛选组件

在前端Web开发中&#xff0c;下拉筛选功能是一种非常常见的交互方式&#xff0c;它可以帮助用户快速选择所需的选项。本文将介绍如何利用Vue.js和uni-app框架来实现一个高效的下拉筛选功能。通过使用这两个强大的前端框架&#xff0c;我们可以轻松地创建具有响应式用户操作的下…

Sublime Text 4 激活教程(Windows+Mac)

下载安装 官网 https://www.sublimetext.com 点击跳转 2023.7.21 版本为4143 Windows激活方式 一、激活License方式 入口在菜单栏中"Help” -> “Enter License” 注意格式&#xff0c;可能会过期失效&#xff0c;失效就用方式二 Mifeng User Single User License E…

Linux底层

一. arm基础知识 基础&#xff1a;c语言 具有一定硬件基础 特点---》前后联系 arm目标&#xff1a; 看懂简单的汇编代码 会看电路图、芯片手册 学会如何用软件控制硬件思想 解决问题的办法 谈谈对嵌入式的理解&#xff1f; 以计算应用为中心&#xff0c;软硬件可裁剪的…

Cloudreve搭建云盘系统,并实现随时访问

文章目录 1、前言2、本地网站搭建1.环境使用2.支持组件选择3.网页安装4.测试和使用5.问题解决 3、本地网页发布1.cpolar云端设置2.cpolar本地设置 4、公网访问测试5、结语 1、前言 自云存储概念兴起已经有段时间了&#xff0c;各互联网大厂也纷纷加入战局&#xff0c;一时间公…

ONNX Runtime 加速深度学习(C++ 、python)详细介绍

ONNX Runtime 加速深度学习(C 、python)详细介绍 本文在 https://blog.csdn.net/u013250861/article/details/127829944 基础上进行了更改&#xff0c;感谢原作&#xff01; ONNXRuntime(Open Neural Network Exchange)是微软推出的一款针对ONNX模型格式的推理框架&#xff0c…

妙记多 Mojidoc PC端(Mac 端+windows端)Beta版本正式上线!

你们呼唤了无数次的妙记多 Mojidoc PC客户端 Beta版本正式上线啦&#xff01; 感谢300位妙友积极参与内测&#xff0c;给予了我们很多非常有效的意见和建议&#xff01;我们会根据用户反馈不断优化和修复相关功能&#xff0c;在此感谢妙友们一直以来的支持&#xff5e; PC端拥…

SkyWalking链路追踪中span全解

基本概念 在SkyWalking链路追踪中&#xff0c;Span&#xff08;跨度&#xff09;是Trace&#xff08;追踪&#xff09;的组成部分之一。Span代表一次调用或操作的单个组件&#xff0c;可以是一个方法调用、一个HTTP请求或者其他类型的操作。 每个Span都包含了一些关键的信息&am…

小程序 methods方法互相调用 this.onClickCancel is not a function

背景 做了一个自定义的弹出对话窗口&#xff0c;主要是自定义一些文本颜色。 问题 但是点击按钮事件&#xff1a;取消与确认&#xff0c;调用了同一个接口&#xff0c;然后想着走不同方法&#xff0c;需要调用methods其他方法。然后报错了&#xff1a; VM1081 WAService.js:…

行为型模式 - 状态模式

概述 【例】通过按钮来控制一个电梯的状态&#xff0c;一个电梯有开门状态&#xff0c;关门状态&#xff0c;停止状态&#xff0c;运行状态。每一种状态改变&#xff0c;都有可能要根据其他状态来更新处理。例如&#xff0c;如果电梯门现在处于运行时状态&#xff0c;就不能进…

C语言数据在内存中的存储

目录 前言 本期内容介绍 一、数据类型的介绍 1.1类型的意义&#xff1a; 1.2C语言中是否有字符串类型&#xff1f; 1.3类型的基本归类 整型家族&#xff1a; 浮点型&#xff08;实型&#xff09;家族&#xff1a; 构造&#xff08;自定义&#xff09;类型&#xff1a;…

STM32外设系列—TB6612FNG

本文涉及到定时器和串口的知识&#xff0c;详细内容可见博主STM32速成笔记专栏。 文章目录 一、TB6612简介二、TB6612使用方法2.1 TB6612引脚连接2.2 控制逻辑2.3 电机调速 三、实战项目3.1 项目简介3.2 初始化GPIO3.3 PWM初始化3.3 电机控制程序3.4 串口接收处理函数 一、TB66…

优化transformer

使用transformer而导致的时间长&#xff0c;可能会由于self-attention计算Query和key的值才导致的时间长&#xff0c;也可能会因为feed forward中的计算导致时间长。这里我们只针对第一种情况下进行优化。 第一种情况&#xff1a;有些问题&#xff0c;我们可能不需要看整个句子…

【问题总结】基于docker-compose实现nginx转发redis

目录&#xff1a; 文章目录 需求简介&#xff1a;Q1: nginx的http模块和http模块有什么不同Q2: 可以都使用stream模块进行配置吗 Docker环境下如何转发1 修改docker-compose2 修改nginx.conf3 测试连接 需求简介&#xff1a; 需要在192.168.3.11的ngnix上&#xff0c;转发192.…

前端 | ( 十)HTML5简介及相关新增属性 | 尚硅谷前端html+css零基础教程2023最新

学习来源&#xff1a;尚硅谷前端htmlcss零基础教程&#xff0c;2023最新前端开发html5css3视频 系列笔记&#xff1a; 【HTML4】&#xff08;一&#xff09;前端简介【HTML4】&#xff08;二&#xff09;各种各样的常用标签【HTML4】&#xff08;三&#xff09;表单及HTML4收尾…

MyBatis学习笔记——4

MyBatis学习笔记——4 一、MyBatis的高级映射及延迟加载1.1、多对一1.1.1、第一种方式&#xff1a;级联属性映射1.1.2、第二种方式&#xff1a;association1.1.3、第三种方式&#xff1a;分步查询 1.2、一对多1.2.1、第一种方式&#xff1a;collection1.2.1、第二种方式&#x…

Web后端开发总结

后端web开发大致流程 和对应的核心技术 对应技术的来源 springMVC可以理解为spring框架中的web开发框架 springMVCSpringMybatis就是我们熟知的ssm框架了

golang单元测试及mock总结

文章目录 一、前言1、单测的定位2、vscode中生成单测 二、构造测试case的注意事项1、项目初始化2、构造空interface{}3、构造结构体的time.Time类型4、构造json格式的test case 三、运行单测文件1、整体运行单测文件2、运行单个单测文件报错&#xff08;1&#xff09;command-l…

基于sklearn计算precision、recall等分类指标

文章目录 一、分类指标函数1.1 precision_score函数1.2 recall_score函数1.3 accuracy_score函数1.4 f1_score函数1.5 precision_recall_curve函数1.6 roc_curve函数1.7 roc_auc_score函数1.8 classification_report函数 二、二分类任务三、多分类任务3.1 Macro Average&#x…