STL——vector模拟实现

在学习过程种 ,学习看源码是很有必要的,它可以让你更清楚的知道一些代码的细节,你也会发现源码将效率利用到了极致,不得不佩服写出源码的人。

下面我将配合源码来实现一个简单的vector,下面请看源码

看源码我们首先要看的就是成员变量,我们可以看到源码中有迭代器的start、finish、end_of_storage三个成员变量,然后可以看到它将一些类型进行重命名。我们可以将它理解为下面的这张图。


其次我们接下来看它的构造函数,它提供了无参和带参的构造函数,看到有fill_initialize这个函数,不难猜一猜可能和初始化有关。这里就不将它展开说了,有兴趣的可以去看看《STL源码剖析》这本书。

学习了vector,可以知道resize是一个改变vector的finish

  • 如果传入new_size比有效元素少,就将后面的元素删除
  • 如果传入的new_size比有效元素多,那么就在最后加上x

与resize相对应的就是reserve函数了,它是改变vector的end_of_storage

  • 如果开辟的容量大于end_of_storage,那么就开辟一个n个空间的大小
  • 然后将数据拷贝到新空间中,然后将旧空间释放掉
  • 最后改变start的指向

但是这里注意一下,当发生数据拷贝的时候,是不能直接进行memcpy,要知道vector中存放的是一个T类型,如果T是string,那么当发生memcpy的时候就会发生浅拷贝,里面string指向的是一块释放了的空间。

接下来我们看一下insert函数

  • 关于insert,首先我们要知道当进行插入操作时就有可能触发扩容,那么就有可能触发reserve函数,那么就有可能空间释放的问题,所以不能memmove。

所以,了解了一些特殊情况,就可以实现了。

template <class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;vector(): start(nullptr), finish(nullptr), end_of_storage(nullptr){}vector(size_t n, const T &value){push_back(value);}explicit vector(size_t n){for (int i = 0; i < n; i++){push_back(T());}}template<class InputIterator>vector(InputIterator first,InputIterator last){while(first != last){push_back(*first);++first;}}vector(int n, const T &value = T()){resize(n, value);}vector(long n, const T &value = T()){resize(n, value);}// v2(v1)vector(const vector<T> &v){reserve(v.capacity());for (auto e : v){push_back(e);}}//v2 = v1vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){if (start){delete[] start;start = finish = end_of_storage = nullptr;}}iterator begin(){return start;}const_iterator begin() const {return start;}iterator end(){return finish;}const_iterator end() const {return finish;}size_t size() const{return finish - start;}size_t max_size() const{return size_t(-1) / sizeof(T);}bool empty() const {return start == finish;}void swap(vector<T> &v){::swap(start, v.start);::swap(finish, v.finish);::swap(end_of_storage, v.end_of_storage);}void resize(size_t n, T val = T()){// 如果n > size()就开空间,将val插入到后面if (n > size()){reserve(n);while (finish < start + n){*finish = val;++finish;}}else{// 将有效空间变小finish = start + n;}}void reserve(size_t n){if (n > capacity()){size_t old = size();// 申请新空间T *tmp = new T[n];if (start){// memcpy(tmp,start,sizeof(T)*old);// 之所以不能用memcpy,是因为如果是自定义类型,深拷贝的时候就会访问释放了的空间了// 当然,这里可以用引用计数或者移动构造、移动赋值来搞定这个问题。for (size_t i = 0; i < old; i++){tmp[i] = start[i];}delete[] start;}start = tmp;finish = start + old;end_of_storage = start + n;}}size_t capacity() const{return end_of_storage - begin();}void push_back(const T &x){if (finish != end_of_storage){*finish = x;++finish;}else{size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();reserve(newcapacity);*finish = x;++finish;}}void pop_back(){assert(size() > 0);--finish;}iterator erase(iterator pos){assert(pos >= start);assert(pos < finish);// 将pos之后的元素从后往前移动iterator it = pos + 1;while (it < finish){*pos = *it;it++;}--finish;return pos;}iterator insert(iterator pos,const T& x){assert(pos <= finish && pos >= start);if(finish == end_of_storage){size_t len = pos - start;reserve(capacity() == 0 ? 4 : 2*capacity());pos = start + len;}iterator  end = finish;while(pos < end){*end = *(end-1);--end;}*pos = x;++finish;return pos;}T &operator[](size_t n){assert(n <= size());return *(begin() + n);}const T &operator[](size_t pos) const {assert(pos >= start);assert(pos < finish);return start[pos];}private:iterator start = nullptr;iterator finish = nullptr;iterator end_of_storage = nullptr;};

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

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

相关文章

React16源码: React中的completeUnitOfWork的源码实现

completeUnitOfWork 1 &#xff09;概述 各种不同类型组件的一个更新过程对应的是在执行 performUnitOfWork 里面的 beginWork 阶段它是去向下遍历一棵 fiber 树的一侧的子节点&#xff0c;然后遍历到叶子节点为止&#xff0c;以及 return 自己 child 的这种方式在 performUni…

Kotlin程序设计 扩展篇(一)

Kotlin程序设计&#xff08;扩展一&#xff09; **注意&#xff1a;**开启本视频学习前&#xff0c;需要先完成以下内容的学习&#xff1a; 请先完成《Kotlin程序设计》视频教程。请先完成《JavaSE》视频教程。 Kotlin在设计时考虑到了与Java的互操作性&#xff0c;现有的Ja…

嵌入式培训机构四个月实训课程笔记(完整版)-C++和QT编程第五天-Qt 常见问题(物联技术666)

链接:https://pan.baidu.com/s/1GASCCewISEb6zJYOStmg6g?pwd=1688 提取码:1688 1 QWidget类有什么用途? 在Qt应用程序中,QWidget用做工作空间.它是底层窗口,在其上可以放置其他对象,如按钮等. 2 a.setMainWidget(&mainwindow);语句的意义是什么? 这段代码告诉Qt,说明m…

《Python数据分析技术栈》第06章使用 Pandas 准备数据 01 Pandas概览(Pandas at a glance)

01 Pandas概览&#xff08;Pandas at a glance&#xff09; 《Python数据分析技术栈》第06章使用 Pandas 准备数据 01 Pandas概览&#xff08;Pandas at a glance&#xff09; Pandas概述 Wes McKinney developed the Pandas library in 2008. The name (Pandas) comes from…

像素图片在网页中很模糊怎么办?输入这个样式

像素图片在网页中很模糊怎么办&#xff1f;输入这个样式 image-rendering: pixelated;输入前 输入后

业务逻辑漏洞—验证码绕过

验证码绕过第一关&#xff1a; 前端验证码绕过&#xff1a; 打开pikachu靶场&#xff1a; 输入错误的验证码时会出现弹窗&#xff08;alert&#xff09;此时我们猜测这可能存在着前端限制 如果验证码有前端限制&#xff08;只在前端有作用&#xff09;&#xff0c;不影响后…

(十一)Head first design patterns状态模式(c++)

状态模式 如何去描述状态机&#xff1f; 假设你需要实例化一台电梯&#xff0c;并模仿出电梯的四个状态&#xff1a;开启、关闭、运行、停止。也许你会这么写 class ILift{ public:virtual void open(){}virtual void close(){}virtual void run(){}virtual void stop(){} }…

基于SpringBoot Vue二手闲置物品交易系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

4小时精通MyBatisPlus框架

目录 1.介绍 2.快速入门 2.1.环境准备 2.2.快速开始 2.2.1引入依赖 2.2.2.定义Mapper ​编辑 2.2.3.测试 2.3.常见注解 ​编辑 2.3.1.TableName 2.3.2.TableId 2.3.3.TableField 2.4.常见配置 3.核心功能 3.1.条件构造器 3.1.1.QueryWrapper 3.1.2.UpdateWra…

Flowable 加签和减签

一&#xff1a;示例 Deployment deploy repositoryService.createDeployment().name("会签流程").addClasspathResource("processes/CounterSignProcess.bpmn").deploy();ProcessInstance processInstance runtimeService.startProcessInstanceByKey(&qu…

【操作系统】同步和互斥详细讲解(算法+源码)

博主介绍&#xff1a;✌全网粉丝喜爱、前后端领域优质创作者、本质互联网精神、坚持优质作品共享、掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战✌有需要可以联系作者我哦&#xff01; &#x1f345;附上相关C语言版源码讲解&#x1f345; &#x1f44…

hot100:11滑动窗口的最大值

题目链接&#xff1a; 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 算法思想&#xff1a; 法一&#xff08;暴力&#xff09;&#xff1a; 暴力的算法是我刚开始做这个题目使用的方法&#xff0c;通过了测试用例&#xff0c;但是提交的时候超出…

记录一次从有道云笔记迁移到语雀笔记

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 1、安装git&#xff0c;python3等准备工作 文章中标注python3&#xff0c;为避免与python2 冲…

【Java-框架-SpringSecurity】单点登录(认证和授权)- 随笔

项目文件&#xff1b; 【1】 【2】 【3】 【4】 【5】 【6】 【7】 【8】

SpringBoot 连接 OceanBase 数据库示例程序报错连接被拒绝

使用OceanBase官方的&#xff1a;SpringBoot 连接 OceanBase 数据库示例 1. 解释一&#xff1a; jdbc:oceanbase://host:port/schema_name?user$user_name&password$password&useSSLfalse&useUnicodetrue&characterEncodingutf-8参数说明&#xff1a; host&…

Redis常见数据结构以及使用场景分别是什么

String String数据结构是简单的key-value类型&#xff0c;value其实不仅可以是String&#xff0c;也可以是数字。 常规key-value缓存应用&#xff1b; 常规计数&#xff1a;微博数&#xff0c;粉丝数等。 #Hash Hash 是一个 string 类型的 field 和 value 的映射表&#xff…

【小白学机器学习3】关于最简单的线性回归,和用最小二次法评估线性回归效果, 最速下降法求函数的最小值

目录 1 什么是回归分析 1.1 什么是线性回归 1.2非线性回归 2 数据和判断方法 2.1 原始数据 2.2 判断方法&#xff1a;最小二乘法 3 关于线性回归的实测 3.1 用直线模拟 3.2 怎么判断哪个线性模拟拟合更好呢&#xff1f; 3.2.1 判断标准 3.2.2 最小二乘法 3.2.3 高维…

【征服redis16】收官-redis缓存一致性问题解决方案

今天我们来写redis最后一篇&#xff1a;redis作为缓存时如何与数据库实现数据一致的问题。 最近看redis看得有点麻了&#xff0c;这篇就简单描述吧 目录 1.什么是缓存与数据库一致性问题 1.1 缓存一致性的概念 1.2 缓存不一致的场景 2.缓存不一致的解决思路 1.什么是缓存…

HarmonyOS 通过Web组件嵌套网络应用

我们今天来说说 在程序中嵌套一个网址地址 HarmonyOS中是通过一个简单的WEB组件来实现 网络应用就是相当于网址地址 通过链接将应用嵌入到手机当中 WEB组件需要两个参数 一个是 src 地址 要嵌套的网址 另一个是 控制器 我们可以先编写代码如下 import webview from "o…