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

C++vector 简单实现

一。概述

vector是我们经常用的一个容器,其本质是一个线性数组。通过对动态内存的管理,增删改查数据,达到方便使用的目的。
作为一个线性表,控制元素个数,容量,开始位置的指针分别是

start  /*是数组的首地址*/
finish /*是数组元素的终止位置,看下图*/
end_of_storage/*是数组元素的总容量,看下图*/

大概的样子:
在这里插入图片描述
我们通过操作此三个指针和内存的增加减少或者复制转移的方式完成vector的成员方法。
下面是类成员定义的展示:

template<class _Ty> #类模板中没 有内存分配器,我们在函数中自己malloc实现#
class MyVector
{
public:typedef _Ty				value_type;typedef _Ty* pointer;typedef const _Ty* const_pointer;typedef _Ty& reference;typedef const _Ty& const_reference;typedef pointer        iterator;typedef const_pointer  const_iterator;typedef unsigned  int  size_type;
private:_Ty* _M_start;_Ty* _M_finish;_Ty* _M_end_of_storage;public:MyVector() :_M_start(nullptr), _M_finish(nullptr), _M_end_of_storage(nullptr) {}~MyVector() {clear();free(_M_start);}reference at(size_type pos){assert(pos >= 0 && pos < size());//return (*(pos + _M_start));return (_M_start[pos]);}const_reference at(size_type pos) const{assert(pos >= 0 && pos < size());return (*(pos + _M_start));}reference operator[](size_type pos){if (pos >= 0 && pos < size()) {return _M_start[pos];}else {std::cout << "error operator[]";exit(1);}}const_reference operator[](size_type pos) const{if (pos >= 0 && pos < size()) {return _M_start[pos];}else {std::cout << "error operator[]";exit(1);}}reference front(){return *_M_start;}const_reference front() const{return *_M_start;}reference back(){return *(_M_finish -1);}const_reference back() const{return *(_M_finish - 1);}_Ty* data(){return begin(); }const _Ty* data() const{return begin();}public:// 容量size_t size() const{return (size_t)(_M_finish - _M_start);}size_t capacity() const{return (size_t)(_M_end_of_storage - _M_start);}/*2/14*/bool empty()const{return size() > 0 ? true : false;}

二。重点成员方法解析

1.push_back尾部添加元素
不管pushback进的值是内置类型还是类类型,都应该是先创建一个空间,在此基础上生成对象实例化。实例化是在构造函数中进行的。
我们也要知道的是,一个进程的地址空间是4G,给定的数据(只读或是读、写数据)是固定大小,一旦容器像临时数组arr[100]的定义,那么的成员所占的内存如果过大或是动态的增减的难度,那么势必会不方便容器的使用,也不方便管理,所以使用动态内存来进行管理。

void push_back(const _Ty& val){if (_M_finish != _M_end_of_storage){new(_M_finish)_Ty(val);++_M_finish;}else {_M_insert_aux(end(),val);}}

_M_insert_aux 函数实现

_M_insert_aux函数中有一部分是从源空间的元素复制到新位置,此时挨个遍历,原位构造的方式相比于连续空间的赋值构造,我猜测后者效率更高一些(从cpuj计算的角度)。

		void _M_insert_aux(iterator pos, const _Ty& val) //{//const size_t oldsize = size();const size_t len = size() != 0 ? (size() * 1.5 + 1) : 1;//iterator new_start = (_Ty*)malloc(sizeof(_Ty) * len);iterator  start2 = (_Ty*)malloc(sizeof(_Ty) * len);//eg1:开始复制数据到新内存iterator newstart = start2;iterator newfinsh = _M_start;/*while (newfinsh != pos){new(newstart)_Ty(*newfinsh);++newstart;++newfinsh;}*//*new(newstart)_Ty(val);++newstart;*///eg1的另一种写法,测试:while (newfinsh != pos){memcpy(start2, _M_start, sizeof(_Ty)*(_M_finish-_M_start));newstart = _M_finish - _M_start + start2;newfinsh = _M_finish;}new(newstart)_Ty(val);++newstart;iterator it = _M_finish;while (newfinsh != _M_end_of_storage){++newfinsh;++newstart;}for (iterator it = _M_start; it != _M_finish; it++){it->~_Ty();}free(_M_start);_M_finish = newstart;_M_end_of_storage = len + start2;_M_start = start2;}

**2.operator =移动赋值
次函数需要注意的是什么形式时编译器调用的是赋值重载,什么形式时会调用拷贝构造。
隐式的拷贝构造:在创建对象性时的赋值,比如;
MyVector<Int
> tmp= arr;
显示的拷贝构造则是:
MyVector<Int
> tmp(arr);
如果你使用vector时的写法是隐式的,那么会调用拷贝构造完成对像的复制;
相反你使用显示的方式创建对象,也是会调用拷贝构造。
当你在创建对象后的赋值运算符的重载时才会调用vector的移动赋值函数

MyVector& operator= (const MyVector& V1)//在赋值运算符重载中不能在调用拷贝构造//因为this已经是一个对象,再拷贝构造创建一个对象,//是没什么意义的事情。{//arr.operator(V1);if (V1._M_start == nullptr&&_M_start ==nullptr) {return *this;}else if (this->_M_start == nullptr) { //拷贝构造/*iterator start = (_Ty*)malloc(sizeof(_Ty) * V1.capacity());_M_start = start;*/const_iterator it = V1.begin();while (it != V1._M_finish) {this->push_back(*it);++it;}/*_M_finish = ( _Ty* )it;_M_end_of_storage = V1.capacity()+_M_start;*/return *this;}else if (this->_M_start != nullptr) {if (this->size() >= V1.size()){/*for (iterator it = _M_start; it != _M_finish; ++it){it->~_Ty();}*/this->clear();iterator it = (_Ty*)V1.begin();while (it != V1._M_finish) {this->push_back(*it);++it;}return *this;}else {this->clear();free(_M_start);_M_start = nullptr;_M_finish = nullptr;this->_M_end_of_storage = nullptr;/*	iterator start = (_Ty*)malloc(sizeof(_Ty) * V1.capacity());_M_start = start;*/iterator it = (_Ty*)V1.begin();//iterator it =V1._M_start;while (it != V1._M_finish) {this->push_back(*it);++it;}/*_M_finish = it;_M_end_of_storage = V1.capacity() + _M_start;*/return *this;}}}

3.拷贝构造
注意:在类的成员方法内部不要在类中几个默认的成员函数(构造,析构,赋值重载,取地址运算符的重载)中调用拷贝构造,没有什么意义。从面向对象编程的角度讲不符合现实世界的逻辑。

MyVector(const MyVector& V1){cout << this << endl;iterator start = (_Ty*)malloc(sizeof(_Ty) * V1.capacity());if (start == nullptr){std::cout << "malloc error" << std::endl;exit(1);}iterator finish = start;iterator p = V1._M_start;_M_start = start;while (p != V1._M_finish){new(finish)_Ty(*p);++p;++finish;}_M_finish = finish;_M_end_of_storage = _M_start + V1.capacity();}

4.erase

iterator erase(iterator _F, iterator _L){if (_F != _L){if (_L != _M_finish) copy(_L, _M_finish, _F);_M_finish = _M_finish - (_L - _F);memset(_M_finish , 0x00, sizeof(_Ty) * (_L - _F));}return _L;}iterator erase(iterator pos)//有返回值,迭代器返回{return erase(pos, pos + 1);/*if (pos != end()) //这个代码可被erase(pos,pos+1)替代{copy(pos+1,_M_finish,pos);(--_M_finish)->~_Ty();}return pos;*/}

需要注意的是,上面使用到memcpy/memmove/copy函数时,不能保证对有虚函数的类(能产生多态的类)可以继续使用多态。原因是虚函数表和虚表指针丢失,无法找到函数指针(虚表指针应该不丢失)。

相关文章:

C++vector 简单实现

一。概述 vector是我们经常用的一个容器&#xff0c;其本质是一个线性数组。通过对动态内存的管理&#xff0c;增删改查数据&#xff0c;达到方便使用的目的。 作为一个线性表&#xff0c;控制元素个数&#xff0c;容量&#xff0c;开始位置的指针分别是&#xff1a; start …...

通用缓存存储设计实践

目录介绍 01.整体概述说明 1.1 项目背景介绍1.2 遇到问题记录1.3 基础概念介绍1.4 设计目标1.5 产生收益分析 02.市面存储方案 2.1 缓存存储有哪些2.2 缓存策略有哪些2.3 常见存储方案2.4 市面存储方案说明2.5 存储方案的不足 03.存储方案原理 3.1 Sp存储原理分析3.2 MMKV存储…...

sheng的学习笔记Eureka Ribbon

Eureka-注册中心Eureka简介官方网址&#xff1a;https://spring.io/projects/spring-cloud-netflixEureka介绍Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现(请对比Zookeeper)。Zooleeper nacos.Eureka 采用了 C-S 的设计架构。Eureka Server 作为服…...

零代码工具我推荐Oracle APEX

云原生时代零代码工具我推荐Oracle APEX 国内的低码开发平台我也看了很多&#xff0c;感觉还是不太适合我这个被WEB抛弃的老炮。自从看了Oracle APEX就不打算看其它的了。太强大了&#xff0c;WEB服务器都省了&#xff0c;直接数据库到WEB页面。功能很强大&#xff0c;震撼到我…...

InstructGPT方法简读

InstructGPT方法简读 引言 仅仅通过增大模型规模和数据规模来训练更大的模型并不能使得大模型更好地理解用户意图。由于数据的噪声极大&#xff0c;并且现在的大多数大型语言模型均为基于深度学习的“黑箱模型”&#xff0c;几乎不具有可解释性和可控性&#xff0c;因此&…...

SpringCloud-5_模块集群化

避免一台Server挂掉&#xff0c;影响整个服务&#xff0c;搭建server集群创建e-commerce-eureka-server-9002微服务模块【作为注册中心】创建步骤参考e-commerce-eureka-server-9001修改pom.xml,加入依赖同9001创建resources/application.yml9002的ymlserver: # 修改端口号por…...

AQS底层源码深度剖析-BlockingQueue

目录 AQS底层源码深度剖析-BlockingQueue BlockingQueue定义 队列类型 队列数据结构 ArrayBlockingQueue LinkedBlockingQueue DelayQueue BlockingQueue API 添加元素 检索(取出)元素 BlockingQueue应用队列总览图 AQS底层源码深度剖析-BlockingQueue【重点中的重…...

Kotlin协程:Flow的异常处理

示例代码如下&#xff1a;launch(Dispatchers.Main) {// 第一部分flow {emit(1)throw NullPointerException("e")}.catch {Log.d("liduo", "onCreate1: $it")}.collect {Log.d("liudo", "onCreate2: $it")}// 第二部分flow …...

qt下ffmpeg录制mp4经验分享,支持音视频(h264、h265,AAC,G711 aLaw, G711muLaw)

前言 MP4&#xff0c;是最常见的国际通用格式&#xff0c;在常见的播放软件中都可以使用和播放&#xff0c;磁盘空间占地小&#xff0c;画质一般清晰&#xff0c;它本身是支持h264、AAC的编码格式&#xff0c;对于其他编码的话&#xff0c;需要进行额外处理。本文提供了ffmpeg录…...

C#读取Excel解析入门-1仅围绕三个主要的为阵地,进行重点解析,就是最理性的应对上法所在

业务中也是同样的功能点实现。只是多扩展了很多代码&#xff0c;构成了项目的其他部分&#xff0c;枝干所在。但是有用的枝干&#xff0c;仅仅不超过三个主要的&#xff01;所以您仅仅围绕三个主要的为阵地&#xff0c;进行重点解析&#xff0c;就是最理性的应对上法所在了 str…...

一起Talk Android吧(第五百一十八回:在Android中使用MQTT通信五)

文章目录 知识回顾问题描述解决过程经验分享各位看官们大家好,这一回中咱们说的例子是" 在Android中使用MQTT通信五",本章回内容与前后章节内容无关联。闲话休提,言归正转,让我们一起Talk Android吧! 知识回顾 我们在前面章回中介绍了如何使用MQTT通信,包含它…...

100种思维模型之混沌与秩序思维模型-027

人类崇尚秩序与连续性&#xff0c;我们习惯于我们的日常世界&#xff0c;它以线性方式运作&#xff0c;没有不连续或突跳。 为此&#xff0c;我们学会了期望各种过程以连续方式运行&#xff0c;我们的内心为了让我们更有安全感&#xff0c;把很多事物的结果归于秩序&#xff0c…...

Java开发 - Redis初体验

前言 es我们已经在前文中有所了解&#xff0c;和es有相似功能的是Redis&#xff0c;他们都不是纯粹的数据库。两者使用场景也是存在一定的差异的&#xff0c;本文目的并不重点说明他们之间的差异&#xff0c;但会简要说明&#xff0c;重点还是在对Redis的了解和学习上。学完本…...

Python - 使用 pymysql 操作 MySQL 详解

目录创建连接 pymsql.connect() 方法的可传参数连接对象 conn pymsql.connect() 方法游标对象 cursor() 方法使用示例创建数据库表插入数据操作数据查询操作数据更新操作数据删除操作SQL中使用变量封装使用简单使用&#xff1a; import pymysqldb pymysql.connect(host,user…...

机器学习-卷积神经网络CNN中的单通道和多通道图片差异

背景 最近在使用CNN的场景中&#xff0c;既有单通道的图片输入需求&#xff0c;也有多通道的图片输入需求&#xff0c;因此又整理回顾了一下单通道或者多通道卷积的差别&#xff0c;这里记录一下探索过程。 结论 直接给出结论&#xff0c;单通道图片和多通道图片在经历了第一…...

考研复试——计算机组成原理

文章目录计算机组成原理1. 计算机系统由哪两部分组成&#xff1f;计算机系统性能取决于什么&#xff1f;2. 冯诺依曼机的主要特点&#xff1f;3. 主存储器由什么组成&#xff0c;各部分有什么作用&#xff1f;4. 什么是存储单元、存储字、存储字长、存储体&#xff1f;5. 计算机…...

硬件设计 之摄像头分类(IR摄像头、mono摄像头、RGB摄像头、RGB-D摄像头、鱼眼摄像头)

总结一下在机器人上常用的几种摄像头&#xff0c;最近在组装机器人时&#xff0c;傻傻分不清摄像头的种类。由于本人知识有限&#xff0c;以下资料都是在网上搜索而来&#xff0c;按照摄像头的分类整理一下&#xff0c;供大家参考&#xff1a; 1.IR摄像头&#xff1a; IRinfr…...

PTA:C课程设计(2)

山东大学&#xff08;威海&#xff09;2022级大一下C习题集&#xff08;2&#xff09;2-5-1 字符定位函数&#xff08;程序填空题&#xff09;2-5-2 判断回文&#xff08;程序填空题&#xff09;2-6-1 数字金字塔(函数)2-6-2 使用函数求最大公约数(函数)2-6-3 使用函数求余弦函…...

第四章:面向对象编程

第四章&#xff1a;面向对象编程 4.1&#xff1a;面向过程与面向对象 面向过程(POP)与面向对象(OOP) 二者都是一种思想&#xff0c;面向对象是相对于面向过程而言的。面向过程&#xff0c;强调的是功能行为&#xff0c;以函数为最小单位&#xff0c;考虑怎么做。面向对象&…...

Linux 安装npm yarn pnpm 命令

下载安装包 node 下载地址解压压缩包 tar -Jxf node-v19.7.0-linux-x64.tar.xz -C /root/app echo "export PATH$PATH:/app/node-v16.9.0-linux-x64" >> /etc/profile source /etc/profile ln -sf /app/node-v16.9.0-linux-x64/bin/npm /usr/local/bin/ ln -…...

linux SPI驱动代码追踪

一、Linux SPI 框架概述 linux系统下的spi驱动程序从逻辑上可以分为3个部分: SPI Core&#xff1a;SPI Core 是 Linux 内核用来维护和管理 spi 的核心部分&#xff0c;SPI Core 提供操作接口&#xff0c;允许一个 spi master&#xff0c;spi driver 和 spi device 在 SPI Cor…...

Ls-dyna材料的相关学习笔记

Elastic Linear elastic materials -Isotropic:各向同性材料 -orthotropic 正交各向异性的 -anistropic 各向异性的...

Arrays方法(copyOfRange,fill)

Arrays方法 1、Arrays.copyOfRange Arrays.copyOfRange的使用方法 功能&#xff1a; 将数组拷贝至另外一个数组 参数&#xff1a; original&#xff1a;第一个参数为要拷贝的数组对象 from&#xff1a;第二个参数为拷贝的开始位置&#xff08;包含&#xff09; to&#xff1a;…...

AcWing - 蓝桥杯集训每日一题(DAY 1——DAY 5)

文章目录一、AcWing 3956. 截断数组&#xff08;中等&#xff09;1. 实现思路2. 实现代码二、AcWing 3729. 改变数组元素&#xff08;中等&#xff09;1. 实现思路2. 实现代码三、AcWing 1460. 我在哪&#xff1f;&#xff08;简单&#xff09;1. 实现思路2. 实现代码四、AcWin…...

RHCSA-文件的其他命令(3.7)

目录 文件的其他命令&#xff1a; 文本内容统计wc 移动和复制&#xff08;cp&#xff09; 移动 查找文件的路径 压缩和解压缩 .tar&#xff08;归档命令&#xff09; shell-命令解释器 linux中的特殊字符 查看系统上的别名&#xff1a;alias 历史命令&#xff08;his…...

多线程update导致的mysql死锁问题处理方法

最近想起之前处理过的一个mysql 死锁问题&#xff0c;是在高并发下update批量更新导致的&#xff0c;这里探讨一下发生的原因&#xff0c;以及解决办法&#xff1b; 发生死锁的sql语句如下&#xff0c;其中where条件后的字段是有复合索引的。 update t_push_message_device_h…...

SpringBoot 如何保证接口安全?

为什么要保证接口安全对于互联网来说&#xff0c;只要你系统的接口暴露在外网&#xff0c;就避免不了接口安全问题。 如果你的接口在外网裸奔&#xff0c;只要让黑客知道接口的地址和参数就可以调用&#xff0c;那简直就是灾难。举个例子&#xff1a;你的网站用户注册的时候&am…...

英伟达驱动爆雷?CPU占用率过高怎么办?

又有一新驱动导致CPU占用率过高&#xff1f; 上周英伟达发布531.18显卡驱动&#xff0c;为大家带来了视频超分辨率技术&#xff0c;并为新发布的热门游戏《原子之心》提供支持。 但在安装新驱动后没过不久就有玩家反映&#xff0c;在游戏结束后会出现CPU占用率突然飙升到10%以…...

链表经典面试题【典中典】

&#x1f4af;&#x1f4af;&#x1f4af;链表经典面试题❗❗❗炒鸡经典&#xff0c;本篇带有图文解析&#xff0c;建议动手刷几遍。&#x1f7e5;1.反转链表&#x1f7e7;2.合并两个有序链表&#x1f7e8;3.链表分割&#x1f7e9;4.链表的回文结构&#x1f7e6;5.相交链表&…...

Java泛型深入

一. 泛型的概述和优势 泛型概述 泛型&#xff1a;是JDK5中引入的特性&#xff0c;可以在编译阶段约束操作的数据类型&#xff0c;并进行检查。泛型的格式&#xff1a;<数据类型>&#xff0c;注意&#xff1a;泛型只能支持引用数据类型。集合体系的全部接口和实现类都是…...

网站怎么做?/查询网站服务器

百分点是一个推荐服务的提供商&#xff0c;但是已经转型为大数据解决方案的提供商。 首先看一下大数据与应用画像的关系&#xff0c;现在大数据是炙手可热的&#xff0c;大数据的4个V都比较了解&#xff0c;大数据应该说是信息技术的自然延伸&#xff0c;意味的无所不在的数据…...

西安做网站程序/搜索引擎排名查询

Django模型Django 对各种数据库提供了很好的支持&#xff0c;包括&#xff1a;PostgreSQL、MySQL、SQLite、Oracle。 Django 为这些数据库提供了统一的调用API。 我们可以根据自己业务需求选择不同的数据库。 MySQL 是 Web 应用中最常用的数据库。本章节我们将以 Mysql 作为实例…...

深圳做网站公司有哪些/seo网站优化推广教程

转自&#xff1a;https://www.cnblogs.com/whiteMu/p/5378747.html 一、display:box; 在元素上设置该属性&#xff0c;可使其子代排列在同一水平上&#xff0c;类似display:inline-block;。 二、可在其子代设置如下属性 前提&#xff1a;使用如下属性&#xff0c;必须在父代设置…...

wordpress创建搜索框/seo自学

POJ-1363 地址:http://poj.org/problem?id1363 直接贴关键代码来分析: int j0;for(int i0;i<n;i){s.push(i1);while(!s.empty() && s.top()num[j]){s.pop();j;}} 上面这个for循环模拟,可以判断出栈顺序的合法性,比较s.top和num[j],其中,主要看计数器j的次数是否与n…...

wordpress用户勾选/平台seo什么意思

SRM&#xff1a;机房内部竞赛&#xff0c;哼唧。 描述 给一个 01 串设为其 S&#xff0c;询问是否存在只出现两次的 01 串 T。 这里的出现定义为存在一串下标 &#xff0c;满足 且 。 输入格式 一行&#xff0c;一个 01 串 输出格式 一行&#xff0c;字母 Y 表示存在&#xff…...

景观设计公司利润/谷歌优化是什么意思

ftp服务很重要&#xff0c;这里介绍ftp在linux上不连接mysql数据库的搭建方法&#xff0c;ftp也可以连接mysql&#xff0c;有时间再生成文档。先说明ftp的基本原理&#xff1a;FTP &#xfffd;File Transfer Protocol 文件传输协议。能够在网络上提供文件传输服务&#xff0c;…...