[C++随笔录] vector模拟实现

vector模拟实现

  • 基本结构
  • 天选之子
    • 构造
    • 拷贝构造
    • 析构
    • operator=
  • 空间
    • reserve
    • resize
    • size && capacity
    • insert
    • push_back
    • erase
    • pop_back
  • 查 && 改
    • swap
    • operator[]
  • 源码

基本结构

// 可以是不同类型, 用类模板
template <class T>
class vector
{
public:// 源码里面成员变量的类型用的是迭代器,// 所以, 先定义迭代器类型typedef T* iterator;typedef const T* const_iterator;private:iterator _start = nullptr; // 相当于string类中的 _striterator _finish = nullptr; // 相当于string类中的 _sizeiterator _endofstorage = nullptr; // 相当于string类中的 _capacity
}
  1. 成员变量先给缺省值, 便于后面的构造函数 和 拷贝构造函数
  2. 迭代器是 T* , 跟string类中 迭代器是 char* 是一样的道理

天选之子

构造

  1. 默认构造函数
vector():_start(nullptr), _finish(nullptr), _endofstorage(nullptr)
{}

由于我们给成员变量都给了缺省值, 那么👇👇👇

vector()
{
}
  1. 开空间 + 初始化
    开空间 + 初始化 也是 resize 干的事情, 那么我们就可以直接复用
vector(int n, const T& val = T()) // 缺省值给T的默认构造出来的对象
{resize(n, val);
}
  1. 迭代器区间初始化

从上一篇文章得出: 同类型, 不同类型, 数组的区间都可以进行初始化. 迭代器多样化 ⇒ 套用模版
⇒ 进而我们得出: 在模版中可以套用模版

template <class InputIterator>
vector(InputIterator first, InputIterator last)
{int n = last - first;resize(n);int i = 0;while (first != last){_start[i++] = *first;first++;}}

拷贝构造

vector(const vector<T>& tem)
{// 找一块新空间 -- 外部深拷贝_start = new T[tem.capacity()];// memcpy(_start, tem._start, tem.capacity); -- 内部浅拷贝, 是错误的for (int i = 0; i < tem.size(); i++) // 内部深拷贝{_start[i] = tem[i];}// 更新size 和 capacity_finish = _start + tem.size();_endofstorage = _start + tem.capacity();}
  • 不能使用memcpy来进行拷贝数据的原因 && 外部和内部的深拷贝图示

析构

~vector()
{// 释放空间delete[] _start;// 置空_start = _finish = _endofstorage = nullptr;
}

operator=

// 现代写法 -- 传值传参, 巧借拷贝构造
T& operator=(const T tem)
{swap(tem);return *this;
}

空间

reserve

void reserve(size_t n)
{assert(n > 0);if (n > capacity()){size_t sz = size();  // 应该先保存一份sz <== _start会发生变化T* tem = new T[n];// 拷贝数据// memcpy(tem._start, _start, n); // 内部浅拷贝for (int i = 0; i < size(); i++){tem[i] = _start[i]; //调用了T的赋值, 从而实现深拷贝}// 更新_startdelete[] _start;_start = tem;// 更新size 和 capacity_finish = _start + sz;_endofstorage = _start + n;}}

resize

void resize(size_t n, const T& val = T())
{assert(n > 0);// 缩if (size() > n){_finish = _start + n;}// 扩else{reserve(n); // 先开n个空间// 从_finish位置开始初始化for (int i = size(); i < size() + n; i++){_start[i] = val;}// 改变_finish_finish = _finish + n;}
}

size && capacity

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

insert

void insert(iterator pos, const T& val = T())
{assert(pos >= _start && pos <= _finish);size_t len = pos - _start; // 在扩容前, 先保存一下pos的相对位置, 以免异地扩容, _start发生变化, 导致pos迭代器失效// 是否扩容if (_finish == _endofstorage){// 考虑到首次插入size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);pos = _start + len; // 扩容后, 更新pos}// 往后挪动数据iterator end = _finish - 1; while (end >= pos){*(end + 1) = *end;end--;}// 插入*pos = val;_finish = _finish + 1;}

push_back

void push_back(const T& val = T())
{ 是否扩容//if (_finish == _endofstorage)//{//	size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;//	reserve(newcapacity);//}//*_finish = val;//++_finish;// 复用insertinsert(_finish, val);
}

erase

iterator erase(iterator pos)
{assert(pos >= _start && pos < _finish);// 往前挪动数据iterator it = pos + 1 ;while (it != _finish){*(it - 1) = *it;it++;}// 更新size--_finish;return pos;
}

pop_back

void pop_back()
{// 复用erase, 传参_finish - 1erase(--end());}

查 && 改

swap

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

operator[]


T& operator[](size_t n)
{return _start[n];
}const T& operator[](size_t n)const 
{return _start[n];
}

源码

#pragma once#include<assert.h>
#include<iostream>namespace muyu
{template <class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin() {return _start;}iterator end() {return _finish;}const_iterator begin()const{return _start;}const_iterator end()const{return _finish;}vector(){}vector(int n, const T& val = T()) // 缺省值给	T的默认构造出来的对象{resize(n, val);}template <class InputIterator>vector(InputIterator first, InputIterator last){int n = last - first;resize(n);int i = 0;while (first != last){_start[i++] = *first;first++;}}vector(const vector<T>& tem){// 找一块新空间 -- 外部深拷贝_start = new T[tem.capacity()];// memcpy(_start, tem._start, tem.capacity); -- 内部浅拷贝, 是错误的for (int i = 0; i < tem.size(); i++) // 内部深拷贝{_start[i] = tem[i];}// 更新size 和 capacity_finish = _start + tem.size();_endofstorage = _start + tem.capacity();}~vector(){// 释放空间delete[] _start;// 置空_start = _finish = _endofstorage = nullptr;}const size_t size()const{return _finish - _start;}const size_t capacity()const{return _endofstorage - _start;}void reserve(size_t n){assert(n > 0);if (n > capacity()){size_t sz = size();  // 应该先保存一份sz <== _start会发生变化T* tem = new T[n];// 拷贝数据// memcpy(tem._start, _start, n); // 内部浅拷贝for (int i = 0; i < size(); i++){tem[i] = _start[i]; //调用了T的赋值, 从而实现深拷贝}// 更新_startdelete[] _start;_start = tem;// 更新size 和 capacity_finish = _start + sz;_endofstorage = _start + n;}}void resize(size_t n, const T& val = T()){assert(n > 0);if (size() > n){_finish = _start + n;}else{reserve(n); // 先开n个空间// 从_finish位置开始初始化for (int i = size(); i < size() + n; i++){_start[i] = val;}// 改变_finish_finish = _finish + n;}}void push_back(const T& val = T()){ 是否扩容//if (_finish == _endofstorage)//{//	size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;//	reserve(newcapacity);//}//*_finish = val;//++_finish;insert(_finish, val);}void insert(iterator pos, const T& val = T()){assert(pos >= _start && pos <= _finish);size_t len = pos - _start; // 在扩容前, 先保存一下pos的相对位置, 以免异地扩容, _start发生变化, 导致pos迭代器失效// 是否扩容if (_finish == _endofstorage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);pos = _start + len; // 扩容后, 更新pos}// 往后挪动数据iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;end--;}// 插入*pos = val;_finish = _finish + 1;}T& operator[](size_t n){return _start[n];}const T& operator[](size_t n)const {return _start[n];}void swap(vector<T>& tem){std::swap(_start, tem._start);std::swap(_finish, tem._finish);std::swap(_endofstorage, tem._endofstorage);}iterator erase(iterator pos){assert(pos >= _start && pos < _finish);iterator it = pos + 1 ;while (it != _finish){*(it - 1) = *it;it++;}--_finish;return pos;}void pop_back(){// 复用erase, 传参_finish - 1erase(--end());}// 现代写法 -- 传值传参, 巧借拷贝构造T& operator=(const T tem){swap(tem);return *this;}private:iterator _start = nullptr; // 相当于string类中的 _striterator _finish = nullptr; // 相当于string类中的 _sizeiterator _endofstorage = nullptr; // 相当于string类中的 _capacity};
}

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

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

相关文章

git和github的入门操作

之前因为工作中用的都是SVN版本控制工具&#xff0c;没接触过git和github&#xff0c;现在开始深入自学Django框架技术后&#xff0c;看到官网推荐使用git&#xff0c;然后这两天网上查阅了很多文章教程&#xff0c;学到入门操作需要学习的点&#xff0c;太多的知识点要后面慢慢…

Mac配置iTerm样式终端

一、MacOs系统 MacOs中终端使用iTerm2 1. 配置oh-my-zsh oh my zsh 的地址&#xff1a; https//github.com/ohmyzsh/ohmyzsh 插件存放位置&#xff1a;~/.oh-my-zsh/plugins 下载常用的插件 git clone http://github.com/zsh-users/zsh-syntax-highlighting.git 修改配…

英伟达 nvidia 官方code llama在线使用

新一代编程语言模型Code Llama面世&#xff1a;重新定义编程的未来 随着人工智能和机器学习技术的迅速发展&#xff0c;我们现在迎来了一款革命性的大型编程语言模型——Code Llama。该模型是基于Llama 2研发的&#xff0c;为开放模型中的佼佼者&#xff0c;其性能达到了行业领…

React组件化开发

1.组件的定义方式 函数组件Functional Component类组件Class Component 2.类组件 export class Profile extends Component {render() {console.log(this.context);return (<div>Profile</div>)} } 组件的名称是大写字符开头&#xff08;无论类组件还是函数组件…

MyBatisPlus(四)表映射:@TableName

表映射 数据库中的表名&#xff0c;和项目中的实体类名&#xff0c;并不相同&#xff0c;则需要通过注解TableName来进行映射。 未映射前报错示例 数据库表名&#xff1a;tb_user 实体类名&#xff1a;User 测试代码 Autowiredprivate UserMapper userMapper;Testvoid selec…

CUDA和cuDNN的安装

参考资料&#xff1a;https://zhuanlan.zhihu.com/p/83971195 目录 CUDA和cuDNN介绍安装验证 CUDA和cuDNN介绍 CUDA(ComputeUnified Device Architecture)&#xff0c;是显卡厂商NVIDIA推出的运算平台。 CUDA是一种由NVIDIA推出的通用并行计算架构&#xff0c;该架构使GPU能够…

网络初识

一 IP 地址 概念: IP 地址主要用于表示网络主机、其他网络设备&#xff08;如路由器&#xff09;的网络地址。简单说&#xff0c;IP地址用于定位主机的网络地址 格式 IP 地址是一个32为的二进制数&#xff0c;通常被分割为4个“8位二进制数“&#xff08;也就是4个字节&…

排序算法(一)

排序算法(一&#xff09; 冒泡排序选择排序插入排序希尔排序堆排序 冒泡排序 冒泡排序是一种十分稳定的排序&#xff0c;其思想是通过两两比较&#xff0c;改变位置&#xff0c;从而每次让一个数出现在其该出现的位置该排序由于很稳定&#xff0c;所以不论数据是否有序&#xf…

什么是语法糖?Java中有哪些语法糖?

什么是语法糖&#xff1f;Java中有哪些语法糖&#xff1f; 语法糖 语法糖&#xff08;Syntactic Sugar&#xff09;&#xff0c;也称糖衣语法&#xff0c;是由英国计算机学家 Peter.J.Landin 发明的一个术语&#xff0c;指在计算机语言中添加的某种语法&#xff0c;这种语法对…

小米笔试题——01背包问题变种

这段代码的主要思路是使用动态规划来构建一个二维数组 dp&#xff0c;其中 dp[i][j] 表示前 i 个产品是否可以组合出金额 j。通过遍历产品列表和可能的目标金额&#xff0c;不断更新 dp 数组中的值&#xff0c;最终返回 dp[N][M] 来判断是否可以组合出目标金额 M。如果 dp[N][M…

thinkphp8路由

thinkphp8已出来有好一段时间了。这些天闲来无事&#xff0c;研究了下tp8的路由。默认情况下&#xff0c;tp8的路由是在route\app.php的文件里。但在实际工作中&#xff0c;我们并不会这样子去写路由。因为这样不好管理。更多的&#xff0c;是通过应用级别去管理路由。假如项目…

2023华为杯研究生数学建模C题分析

完整的分析查看文末名片获取&#xff01; 问题一 在每个评审阶段&#xff0c;作品通常都是随机分发的&#xff0c;每份作品需要多位评委独立评审。为了增加不同评审专家所给成绩之间的可比性&#xff0c;不同专家评审的作品集合之间应有一些交集。但有的交集大了&#xff0c;则…

conda的安装和使用

参考资料&#xff1a; https://www.bilibili.com/read/cv8956636/?spm_id_from333.999.0.0 https://www.bilibili.com/video/BV1Mv411x775/?spm_id_from333.999.0.0&vd_source98d31d5c9db8c0021988f2c2c25a9620 目录 conda是啥以及作用conda的安装conda的启动conda的配置…

redis如何清空当前缓存和所有缓存

Windows环境下使用命令行进行redis缓存清理 redis安装目录下输入cmdredis-cli -p 端口号flushdb 清除当前数据库缓存flushall 清除整个redis所有缓存keys * 查看所有key值del key 删除指定索引的值 注意&#xff1a; 我们清空缓存的时候&#xff0c;需要确保redis-…

JCEF中js与java交互、js与java相互调用

jcef中js与java相互调用&#xff0c;java与js相互调用&#xff0c;chrome与java相互调用&#xff0c;java与chrome相互调用、jcef与java相互调用 前提&#xff1a;https://blog.csdn.net/weixin_44480167/article/details/133170970&#xff08;java内嵌浏览器CEF-JAVA、jcef、…

Go 常用命令介绍

Go 常用命令 文章目录 Go 常用命令一、Go 常用命令1.1 go build1.1.1 指定输出目录1.1.2 常用环境变量设置编译操作系统和 CPU 架构1.1.3 查看支持的操作系统和CPU架构 1.2 go test1.3 go vet1.4 go clean1.5 go fmt1.6 go get1.7 go install1.8 go tool1.9 go generate1.10 go…

智思Ai企联系统去授权版本+uniapp前后端(内含教程)

智思AI企联系统是一款企业级AI系统&#xff0c;与普通版AI产品相比具备显著差异。该系统允许企业按需选择和定制二开任意功能&#xff0c;以满足不同企业的个性化需求和场景要求。企业可以根据实际业务需求扩展和改进系统功能模块&#xff0c;使之更好地适应企业独特需求。

【word格式】mathtype公式插入 | 段落嵌入后格式对齐 | 字体大小调整 |空心字体

1. 公式嵌入 推荐在线latex编辑器&#xff0c;可以截图转 latex 识别率很高 https://www.latexlive.com/home 美中不足&#xff0c;不开会员每天只能用3次识别。 通过公式识别后&#xff0c;输出选择align环境&#xff0c;然后在mathtype中直接粘贴latex就可以转好。 2.公式…

网络爬虫——HTTP和HTTPS的请求与响应原理

目录 一、HTTP的请求与响应 二、浏览器发送HTTP请求的过程 三、HTTP请求方法 四、查看网页请求 五、常用的请求报头 六、服务端HTTP响应 七、常用的响应报头 八、Cookie 和 Session 九、响应状态码 十、网页的两种加载方法 十一、认识网页源码的构成 十二、爬虫协议…

【Linux 之二】Ubuntu下开发环境的搭建(NFS \ SSH \ FTP \ Smba \ ...)

目前正在进行Linux相关项目的开发&#xff0c;而我的Linux开发是在Ubuntu&#xff08;版本20.04&#xff09;下进行的&#xff0c;为此需要搭建很多Linux相关的开发环境&#xff0c;方便工作的进行。这里主要是对各种开发环境的搭建做一个总结记录&#xff0c;方便后面查阅&…