(C++ STL)vector类的简单模拟实现与源码展示

news/2024/9/18 20:52:58/ 标签: c++, 学习, c++STL

vector类的简单模拟实现

  • 一、前言
  • 二、vector 的成员变量
  • 三、vector 部分函数实现
    • size、capacity
    • reserve
    • resize
    • insert 与注意事项
    • erase
    • 构造、析构、赋值拷贝
  • 四、vector 源代码

以下代码环境为 VS2022 C++。

一、前言

vector类 本质上就是数据结构中的顺序表。(可参考:顺序表的讲解与实现)

接下来我们来简单实现 vector类 和 部分对应函数。

参考:legacy.cplusplus.com中的 std::vector

二、vector 的成员变量

在 vector.hpp 中:

namespace my
{template<class T>class vector{// Vector的迭代器是一个原生指针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;}private:iterator _start = nullptr;        // 指向数据块的开始iterator _finish = nullptr;       // 指向有效数据的尾iterator _endOfStorage = nullptr; // 指向存储容量的尾};
}

vector 的成员变量:

  1. vector 所存储数据的类型不确定,则使用模版。
  2. vector 的迭代器本质是指针变量,指向内存的地址。
  3. vector 有三个成员变量,_start、_finish、_endOfStorage,类型为 iterator。本质上都是指针变量,用来定位 vector 在内存上的位置。

vector 在内存中分布如图:

在这里插入图片描述

  1. 红色方块表示未开辟的空间,绿色方块表示有效数据,蓝色方块表示剩余存储容量。

  2. 这里采用 左闭右开 [ _start,_finish ),即 _start 开始就指向有效元素,_finish 指向最后一个元素的后面,_endOfStorage 同理。

三、vector 部分函数实现

size、capacity

vector 的有效长度和容量,是通过指针计算得到的。

指针 - 指针 得到的是中间的元素个数。

在 my::vector 中:

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

reserve

参考:std::vector::reserve

C++ 规定:

  1. 原空间 小于 需求空间 时,vector 扩容到需求空间或更多。

  2. 原空间 大于或等于 需求空间 时,vector 容量不变。

这里扩容严格按照 2 倍扩容。

在 vector.hpp 中:

template<class T>
void my::vector<T>::reserve(size_t n)
{if (n <= capacity()){return;}size_t newCapacity = capacity() == 0 ? MY_VECTOR_INIT_CAPACITY : capacity() * 2;while (newCapacity < n){newCapacity <<= 1;}iterator newStart = new T[newCapacity];// 只能拷贝内置类型,如 string等非内置类型会失效//memcpy(newStart, _start, sizeof(T) * size());// 使用赋值拷贝for (int i = 0; i < size(); ++i){newStart[i] = _start[i];}_finish = newStart + size();            // 指向代码不能交换位置_endOfStorage = newStart + newCapacity;delete[] _start;_start = newStart;
}

resize

参考:std::vector::resize

在 vector.hpp 中:

template<class T>
void my::vector<T>::resize(size_t n, const T& value)
{if (n > capacity()){reserve(n);iterator it = end();iterator over = begin() + n;while (it != over){*it = value;}}_finish = begin() + n;
}

insert 与注意事项

参考:std::vector::insert

注意:
如果返回类型是在类里定义的,在类外使用时需要加上 typename 确定是类型,否则报错。

如 my::vector<T>::iterator 是类里 typedef 的一个类型,在类外使用时,编译器不能确定它是模版类的类型还是其静态变量,则会报错。

在 vector.hpp 中:

// 编译器不能分辨 my::vector<T>::iterator 是类型还是静态变量,
// 加上 typename 表示其为类型即可解决 
template<class T>   
typename my::vector<T>::iterator my::vector<T>::insert(my::vector<T>::iterator pos, const T& x)
{assert(_start <= pos && pos <= _finish);size_t sz = pos - begin();  // 考虑到扩容后 pos 可能失效,用中间值储存reserve(size() + 1);iterator it = nullptr;for (it = end(); it != begin() + sz; --it){*it = *(it - 1);}*it = x;resize(size() + 1);return it + 1;
}

erase

参考:std::vector::erase

在 vector.hpp 中:

template<class T>
typename my::vector<T>::iterator my::vector<T>::erase(my::vector<T>::iterator pos)
{assert(size() != 0);assert(_start <= pos && pos < _finish);for (iterator it = pos; it != end() - 1; ++it){*it = *(it + 1);}--_finish;return pos;
}

构造、析构、赋值拷贝

参考:std::vector::vector
参考:std::vector::~vector
参考:std::vector::operator=

在 my::vector 中:

        vector() = default; // default 后编译器会自动生成默认构造vector(size_t n, const T& value = T()){reserve(n);resize(n);for (auto& val : *this){val = value;}}vector(int n, const T& value = T()){reserve(n);resize(n);for (auto& val : *this){val = value;}}template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector(const vector<T>& v){reserve(v.capacity());for (auto& val : v){push_back(val);}}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endOfStorage, v._endOfStorage);}vector<T>& operator= (vector<T> v){swap(v);return *this;}~vector(){if (_start != nullptr){delete[] _start;_start = nullptr;}_finish = _endOfStorage = _start;}

四、vector 源代码

在 vector.hpp 中:

#pragma once#include <iostream>
#include <cassert>#define MY_VECTOR_INIT_CAPACITY 4namespace my
{template<class T>class vector{public:// Vector的迭代器是一个原生指针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() = default; // default 后编译器会自动生成默认构造vector(size_t n, const T& value = T()){reserve(n);resize(n);for (auto& val : *this){val = value;}}vector(int n, const T& value = T()){reserve(n);resize(n);for (auto& val : *this){val = value;}}template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector(const vector<T>& v){reserve(v.capacity());for (auto& val : v){push_back(val);}}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endOfStorage, v._endOfStorage);}vector<T>& operator= (vector<T> v){swap(v);return *this;}~vector(){if (_start != nullptr){delete[] _start;_start = nullptr;}_finish = _endOfStorage = _start;}//--------------------------------------size_t size() const{return _finish - _start;}size_t capacity() const{return _endOfStorage - _start;}void reserve(size_t n);void resize(size_t n, const T& value = T());//--------------------------------------T& operator[](size_t pos){return *(begin() + pos);}const T& operator[](size_t pos) const{return *(begin() + pos);}//--------------------------------------void push_back(const T& x){insert(end(), x);}void pop_back(){erase(end() - 1);}iterator insert(iterator pos, const T& x);iterator erase(iterator pos);private:iterator _start = nullptr;        // 指向数据块的开始iterator _finish = nullptr;       // 指向有效数据的尾iterator _endOfStorage = nullptr; // 指向存储容量的尾};}template<class T>
void my::vector<T>::reserve(size_t n)
{if (n <= capacity()){return;}size_t newCapacity = capacity() == 0 ? MY_VECTOR_INIT_CAPACITY : capacity() * 2;while (newCapacity < n){newCapacity <<= 1;}iterator newStart = new T[newCapacity];// 只能拷贝内置类型,如 string等非内置类型会失效//memcpy(newStart, _start, sizeof(T) * size());// 使用赋值拷贝for (int i = 0; i < size(); ++i){newStart[i] = _start[i];}_finish = newStart + size();            // 指向代码不能交换位置_endOfStorage = newStart + newCapacity;delete[] _start;_start = newStart;
}template<class T>
void my::vector<T>::resize(size_t n, const T& value)
{if (n > capacity()){reserve(n);iterator it = end();iterator over = begin() + n;while (it != over){*it = value;}}_finish = begin() + n;
}// 编译器不能分辨 my::vector<T>::iterator 是类型还是静态变量,
// 加上 typename 表示其为类型即可解决 
template<class T>   
typename my::vector<T>::iterator my::vector<T>::insert(my::vector<T>::iterator pos, const T& x)
{assert(_start <= pos && pos <= _finish);size_t sz = pos - begin();  // 考虑到扩容后 pos 可能失效,用中间值储存reserve(size() + 1);iterator it = nullptr;for (it = end(); it != begin() + sz; --it){*it = *(it - 1);}*it = x;resize(size() + 1);return it + 1;
}template<class T>
typename my::vector<T>::iterator my::vector<T>::erase(my::vector<T>::iterator pos)
{assert(size() != 0);assert(_start <= pos && pos < _finish);for (iterator it = pos; it != end() - 1; ++it){*it = *(it + 1);}--_finish;return pos;
}

http://www.ppmy.cn/news/1518781.html

相关文章

Python中的“for循环”:探索其无限潜力

引言 for循环是任何Python程序员工具箱中的必备技能之一。无论是在处理数据时需要遍历数组&#xff0c;还是在编写Web应用时循环处理请求&#xff0c;亦或是进行复杂的算法实现&#xff0c;for循环都能派上大用场。通过掌握for循环的不同用法&#xff0c;我们可以更高效地解决…

谷粒商城实战笔记-269~271-商城业务-订单服务-bug修改

文章目录 一&#xff0c;269-商城业务-订单服务-bug修改二&#xff0c;270-商城业务-订单服务-订单确认页渲染三&#xff0c;271-商城业务-订单服务-订单确认页库存查询四&#xff0c;272-商城业务-订单服务-订单确认页模拟运费效果 一&#xff0c;269-商城业务-订单服务-bug修…

深度学习100问18:什么是负采样

嘿&#xff0c;负采样就像是一个巧妙的“偷懒小妙招”&#xff0c;在自然语言处理的世界里大显身手呢&#xff01; 一、定义及原理 想象一下&#xff0c;你在训练一个语言小魔法师&#xff0c;它的任务是搞清楚词和词之间的关系。就像在 Skip-gram 模型里&#xff0c;要猜出…

JAVA如何使用反射读取注解

在Java中&#xff0c;反射是一种强大的机制&#xff0c;它允许程序在运行时取得任何类的内部信息&#xff0c;并能直接操作任意对象的内部属性及方法。使用反射读取注解是Java注解应用的重要部分。以下将详细介绍如何使用Java反射读取注解&#xff0c;并提供相应的代码例子和运…

浅谈【数据结构】图-图的概念

目录 1、图 1.1图的分类 1.2路径 1.3连通图 2、图的存储结构 2.1数组表示法 谢谢帅气美丽且优秀的你看完我的文章还要点赞、收藏加关注 没错&#xff0c;说的就是你&#xff0c;不用再怀疑&#xff01;&#xff01;&#xff01; 希望我的文章内容能对你有帮助&#xff0c…

华为手机数据丢失如何恢复?

在智能手机普及的今天&#xff0c;华为手机凭借其卓越的性能和用户体验赢得了众多用户的青睐。然而&#xff0c;在使用过程中&#xff0c;我们难免会遇到数据丢失或误删除的情况。面对这一困境&#xff0c;许多用户可能会感到束手无策。别担心&#xff0c;本文将为你提供一份全…

分享一个基于Python的广东热门旅游数据可视化分析系统flask毕设(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

安装vue-cli2.0并创建项目

文章目录 1 安装node2 安装vue-cli3 创建基于webpack模板的项目4 项目结构 1 安装node 之前写的博客中介绍了如何安装&#xff1a;NodeJS的安装【windows】。安装完毕后&#xff0c;可以在命令行中输入node -v和npm -v&#xff0c;若出现版本号&#xff0c;则安装成功。 2 安…

Golang 读取文件

GoLang读取文件需要用到os类去打开文件&#xff0c;然后再用其他方式分析文件里的内容。打开文件比较简单&#xff0c;使用os.Open就可以了&#xff0c;记住用defer关闭就行。但是读取文件内容就头疼了&#xff0c;以文本文件为例子&#xff0c;就有各种方式 读取到byte数组 首…

我如何解决 java.lang.ClassNotFoundException:javax.xml.bind.DatatypeConverter

优质博文&#xff1a;IT-BLOG-CN 问题 我如何解决java.lang.ClassNotFoundException&#xff1a;javax.xml.bind.DatatypeConverter 2024-08-25T02:31:25.46202:00 ERROR 21868 --- [fintonic-oauth] [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet…

亚马逊云(AWS)技术深度解析及代码使用案例

亚马逊云&#xff08;AWS&#xff09;技术深度解析及代码使用案例 引言 亚马逊云&#xff08;Amazon Web Services&#xff0c;简称AWS&#xff09;作为全球云计算技术的首创者和领导者&#xff0c;以其强大的基础设施、丰富的服务种类以及卓越的安全性&#xff0c;持续引领着…

EmguCV学习笔记 VB.Net 第9章 视频操作

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

uniapp小程序实现横屏手写签名

<template><view class"signBox column-me"><!-- 这个是自定义的title-可根据自己封装的title的作为调整 --><status-bar title"电子签名" :bgColor"null"></status-bar><view class"topHint">请…

贪心算法---加油站

题目&#xff1a; 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。 给定两个整数…

用 CSS 实现太阳系运行效果

介绍实现最终效果结语介绍 在编程的浩瀚宇宙中,我们总是在探索能够以最简洁的方式创造出最酷炫效果的方法。而使用 CSS 制作响应式太阳系,绝对能提升你的编程乐趣。 如何用 CSS 实现这个神奇的太阳系呢?关键在于巧妙运用 CSS 的动画、定位和尺寸属性。通过定义不同的元素来…

【论文阅读】基于生成对抗网络的模型窃取方法的研究(2021)

Research on Model Stealing Method Based on Generative Adversarial Networks 提出了一种基于生成对抗网络的模型窃取方法——GBMS(Generative adversarial networks Based Model Stealing method)&#xff0c;GBMS允许攻击者在没有真实数据的情况下训练替代模型&#xff0c;…

数据导出为Excel接口报错:java.io.IOException: UT010029: Stream is closed

在Spring框架中&#xff0c;开发过程中经常需要实现数据的导出功能&#xff0c;尤其是将数据导出为Excel文件。然而&#xff0c;在实现这样的功能时&#xff0c;可能会遇到一些意料之外的错误&#xff0c;比如java.io.IOException: UT010029: Stream is closed。本文将基于一个…

云同步的使用

云同步技术是一种在多个设备或系统之间保持数据一致性的技术&#xff0c;它通常依赖于云存储服务来实现。在Java中&#xff0c;实现云同步功能通常需要与云服务提供商的API进行交互&#xff0c;如Amazon S3、Google Cloud Storage、Microsoft Azure Blob Storage等。 以下是一个…

Web自动化测试实战--博客系统

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;测试&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 1.项目效果展示 2.编写web测试用例 3.自动化测试脚本开发 3.1创建空项目 引…

YeAudio音频工具的介绍和使用

夜雨飘零音频工具 这款Python音频处理工具功能强大&#xff0c;支持读取多种格式的音频文件。它不仅能够对音频进行裁剪、添加混响、添加噪声等多种处理操作&#xff0c;还广泛应用于语音识别、语音合成、声音分类以及声纹识别等多个项目领域。 安装 使用pip安装。 pip ins…