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

【C++】vector容器的模拟实现

目录

一,框架设计

二,构造函数

三,析构函数

四,赋值运算符

五,容器接口的实现

1,迭代器实现

2,“ [] ”运算符的实现

3,swap交换和resize重设大小

4,insert插入和erase删除


介绍:

        本文,我们重点实现vector容器的用法,这里要注意的是vector容器可以接纳任意类型,所以,在实现的时候需使用模板来控制。模拟实现vector重点还要放在构造、析构和赋值运算符重载。


一,框架设计

        vector容器设置中,由于需要接纳各种类型,因此,在框架设计中需要使用模板。除此之外,要想访问未知类型数据,需要使用迭代器来访问。这里,我们设置三个迭代器,分别指向数据块开始位置、有效数据的末尾、存储容量的末尾。

template<class T>
class vector
{
public:
    typedef T* iterator;         
 //数据迭代器
    typedef const T* const_iterator;   //常量迭代器
private:
    iterator _start;                 
// 指向数据块的开始
    iterator _finish;                // 指向有效数据的尾
    iterator _endOfStorage;  // 指向存储容量的尾
};


二,构造函数

        在使用构造函数之前,我们首先要考虑基础的算法设置以方便使用:reverse扩容、capacity容器容量、size容器大小、push_back增添元素、pop_back删除元素。

//获取容器大小

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

//获取容器容量
size_t capacity() const
{
    return _endOfStorage - _start;
}

//容器扩容

void reserve(size_t n)
{
    if (n > capacity())    //只能增容不能缩小
    {
        int newsize = size();
        T* tem = new T[n];
        memcpy(tem, _start, sizeof(T) * newsize);
        if (_start)
        {
            delete[] _start;
        }
        _start = tem;
        _finish = _start + newsize;
        _endOfStorage = _start + n;
    }
}

//增添数据

void push_back(const T& x)
{
    if (capacity() == size())   //这里要注意容量是否够用
    {
        int newcapacity = capacity() == 0 ? 4 : 2 * capacity();
        reserve(newcapacity);
    }
    int newsize = size();
    _start[newsize] = x;
    _finish++;
}

//删除数据

void pop_back()
{
    assert(size() > 0);   //这里要注意容器是否为空
    _finish--;
}

普通构造函数      

        首先,我们先实现无任何传入值的构造函数。这种情况只需初始化容器的各种数据即可,不需要做任何增添。

vector()
{
    _start = _finish = _endOfStorage = nullptr;   //直接将数据设为空
}

        第二种构造方式这里模拟实现构造n个数据,如:vector<int>v(5,8)初始化为5个8。

vector(int n, const T& value = T())
{
    reserve(n);      //这里要先进行扩容
    for (int i = 0; i < n; i++)
    {
        push_back(value);  
    }
}

        第三种构造方式模拟实现迭代器的方式进行构造。因为数据类型未知,所以这里还需要使用模板。

//这里迭代器要使用模板

template<class InputIterator>   

//first指向开始位置,last指向终点的下一位
vector(InputIterator first, InputIterator last)  
{
    int newsize = last - first;  
    reserve(newsize);
    for (int i = 0; i < newsize; i++)
    {
        push_back(*(first + i));
    }
}

拷贝构造函数

        原理跟普通构造函数实现的机制一样,这里就不做过多说明,直接实现代码,如下:

vector(const vector<T>& v)
{
    int newsize = v.capacity();
    reserve(newsize);
    for (int i = 0; i < newsize; i++)
    {
        push_back(v._start[i]);
    }
}


三,析构函数

        析构函数在释放空间之后要记得将数据初始化,以保证安全性。

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


四,赋值运算符

        赋值运算符的实现跟拷贝构造函数实现机制相同。实现拷贝后要返回拷贝后的容器,以便实现连续赋值的情况。

vector<T>& operator= (vector<T> v)
{
    int newsize = v.capacity();
    reserve(newsize);
    for (int i = 0; i < newsize; i++)
    {
        push_back(v._start[i]);
    }
    return *this;
}


五,容器接口的实现

1,迭代器实现

        这里实现begin()、end()、cbegin()、cend()四种常用的迭代器。

//begin()和end()的实现

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

//cbegin()和cend()常量迭代器的实现
const_iterator cbegin() const
{
    const_iterator p = (const_iterator)_start;
    return p;
}
const_iterator cend() const
{
    const_iterator p = (const_iterator)_finish;
    return p;
}

2,“ [] ”运算符的实现

        “ [] ” 运算符实现分为两种,一种是变量的实现,一种是常量const的实现。

//变量实现

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

//常量实现
const T& operator[](size_t pos)const
{
    assert(pos >= 0 && pos < size());
    const T tem = (const T)_start[pos];
    return tem;
}

3,swap交换和resize重设大小

        swap接口实现机制是容器的全部数据实现交换。resize实现时要考虑参数大于容器大小和小于容器大小时的不同情况。

//交换算法

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

//设定大小算法

void resize(size_t n, const T& value = T())
{
    assert(n >= 0);  //防止错误操作
    if (n < size())  //小于容器大小时的情况
    {
        _finish = _start + n;
    }
    else     //大于等于容器大小时的情况
    {
        reserve(n);
        for (int i = 0; i < n - size(); i++)
        {
            push_back(value);
        }
    }
}

4,insert插入和erase删除

        这里实现insert插入要注意的是选择位置时,因为不确定数据类型,因此要在指定迭代器的位置进行插入,最后返回该位置的迭代器。

        erase删除位置与insert插入位置一样,删除迭代器所指向的位置,最后返回该位置的迭代器。

//插入算法,在pos位置下插入数据x

iterator insert(iterator pos, const T& x)
{

    //要考虑指定插入的位置在合理范围之内
    assert(pos >= _start && pos < _finish);
    if (size() == capacity())
    {
        reserve(size() + 1);
    }
    for (iterator it = _finish - 1; it >= pos; it--)
    {
        *(it + 1) = *(it);
    }
    *pos = x;
    return pos;
}

//删除算法,删除pos位置下的数据
iterator erase(iterator pos)
{

    //要考虑指定删除的位置在合理范围之内
    assert(size() > 0);
    assert(pos >= _start && pos < _finish);
    for (iterator i = pos; i < _finish - 1; i++)
    {
        *(i) = *(i + 1);
    }
    _finish--;
    return pos;
}

http://www.lryc.cn/news/265438.html

相关文章:

  • 华为Harmony——ArkTs语言
  • uniapp使用colorUI
  • 浅谈测试自动化selenium之POM模式
  • 什么是事件传播、事件冒泡、事件捕获?
  • 【uniapp】uniapp中本地存储sqlite数据库保姆级使用教程(附完整代码和注释)
  • 微软推出了GPT-RAG:这是一个机器学习库,为在Azure OpenAI上使用RAG模式生产部署大型语言模型(LLMs)提供了企业级参考架构
  • Centos系统升级gcc版本
  • Http---HTTP响应报文
  • iOS 开发设计 App 上架符合要求的截图
  • DRF之引入
  • 【Skynet 入门实战练习】事件模块 | 批处理模块 | GM 指令 | 模糊搜索
  • Web组态可视化编辑器-by组态
  • PDF.js介绍以及使用
  • 经常使用的排序算法
  • msyql 24day 数据库主从 主从复制 读写分离 master slave 有数据如何增加
  • 使用 Taro 开发鸿蒙原生应用 —— 探秘适配鸿蒙 ArkTS 的工作原理
  • Linux下 自定义多线程并发快速压缩解压缩脚本
  • ubuntu20.04下安装pcl_ubuntu安装pcl
  • 阿里云常用配置:日志采集、OSS、RAM 权限策略
  • 回顾丨2023 SpeechHome 第三届语音技术研讨会
  • 【flink】状态清理策略(TTL)
  • 4. 行为模式 - 中介者模式
  • 2015年第四届数学建模国际赛小美赛A题飞机上的细长座椅解题全过程文档及程序
  • 机器学习笔记(二)使用paddlepaddle,再探波士顿房价预测
  • 【Linux】权限篇(二)
  • reduce累加器的应用
  • 助力硬件测试工程师之EMC项目测试。
  • Github 2023-12-23 开源项目日报 Top10
  • Quartz.net 正则表达式触发器
  • 【已解决】修改了网站的class样式name值,会影响SEO,搜索引擎抓取网站及排名吗?