STL之vector容器的介绍与模拟实现

这篇具有很好参考价值的文章主要介绍了STL之vector容器的介绍与模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

所属专栏:C“嘎嘎" 系统学习❤️
🚀 >博主首页:初阳785❤️
🚀 >代码托管:chuyang785❤️
🚀 >感谢大家的支持,您的点赞和关注是对我最大的支持!!!❤️
🚀 >博主也会更加的努力,创作出更优质的博文!!❤️

1. vector简介

vector的文档介绍

  1. vector是表示可变大小数组的序列容器。
  2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素
    进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自
    动处理。
  3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小
    为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是
    一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大
    小。
  4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存
    储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是
    对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
  5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增
    长。
  6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末
    尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list
    统一的迭代器和引用更好。

2. vector容器使用

一下垒列出的都是一些比较重要的接口。

2.1vectord 定义

(constructor)构造函数声明 接口说明
vector()(重点) 无参构造
vector(size_type n, const value_type& val = value_type()) 构造并初始化n个val
vector (const vector& x); (重点) 拷贝构造
vector (InputIterator first, InputIterator last); 使用迭代器进行初始化构造

2.2 vector iterator 的使用

iterator的使用 接口说明
begin +end(重点) 获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置的iterator/const_iterator
rbegin + rend 获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator

2.3 vector 空间增长问题

容量空间 接口说明
size 获取数据个数
capacity 获取容量大小
empty 判断是否为空
resize(重点) 改变vector的size
reserve (重点) 改变vector的capacity

2.4 注意事项

  1. capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。
    这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义
    的。vs是PJ版本STL,g++是SGI版本STL。
  2. reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
  3. resize在开空间的同时还会进行初始化,影响size。

3. vector功能模拟实现

3.1 架构搭建

  • 由于本次的模拟实现是基于STL库源码来模拟实现的,所以我们的本次模拟实现的整体构架是来自STL源码库的

1.首先为了防止与库里面的STL发生冲突,首先就要设置命名空间。
2.其次,从使用vector容器来看,我们容器中可以存放各种数据类型的数据,所以要用到模板。
3.在STL标准库中,使用三个指针来确定容器capacity,size的。_start指向数据块的开始,_finish指向有效数据的尾,_endOfStorage指向存储容量的尾。有了这三个指针,我们可以计算出大小,容量,以及迭代器的返回。

namespace qfw
{
	template<calss T>
	class vector
	{
	public:
		typedef T* iterator;
        typedef const T* const_iterator;
        
		vector()
		{……}
		
		~vector()
		{……}
		
	private:
		iterator _start = nullptr; // 指向数据块的开始
        iterator _finish = nullptr; // 指向有效数据的尾
        iterator _endOfStorage = nullptr; // 指向存储容量的尾
	};
}

3.2 空间控制板块

  1. 返回数据的大小size()
size_t size() const
{
    return _finish - _start;
}
  1. 返回容器的容量capacity()
size_t capacity() const
{
    return _endOfStorage - _start;
}
  1. 修改容器的容量reserve()
    STL之vector容器的介绍与模拟实现,# C“嘎嘎” 系统学习,c++,开发语言
void reserve(size_t n)
{
    if (n > capacity())
    {
        size_t old = size();//记录原来_finish的位置,防止迭代器失效
        T* tmp = new T[n];//开新的的空间
        //将数据拷贝到新的空间
        for (int i = 0; i < old; i++)
        {
            tmp[i] = _start[i];
        }
        //删除旧的空间
        delete[] _start;
        //指向新新空间,更新数据
        _start = tmp;
        _finish = _start + old;
        _endOfStorage = _start + n;
    }
}
  1. 修改容器数据的大小resize()
void resize(size_t n, const T& value = T())
{
    if (n > size())
    {
        reserve(n);
        while (_finish < _start + n)
        {
            *_finish = value;
            ++_finish;
        }
    }
    else
    {
        _finish = _start + n;
    }
}

注意:这里用到的缺省参数的知识点,但是我们容器是可以存放各种数据类型的数据的,所以我们的缺省值因该也是要对应着给对应的缺省值的也就是T()。但是这个也不是好理解,如果是T是string类型的话,string()是一个匿名对象,回去调用string的默认构造,也就是说如果T类型是自定义类型的话说的过来,它回去调用它的默认构造。但是如果T是内置类型的话怎么办,我们之前学习的时候是了解到内置类型是没有默认构造的,那这里怎么说到过去呢?所以为了解决这个问题,C++给内置类型开了后面,允许内置类型有默认构造。

3.3 迭代器

迭代器提供两个版本,const和非const版本。文章来源地址https://www.toymoban.com/news/detail-810843.html

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

const_iterator begin() const
{
    return _start;
}
const_iterator end() const
{
    return _finish;
}

3.4 增加/删除数据

  1. 尾插push_back()
void push_back(const T& x)
{
    if (_finish == _endOfStorage)
    {
        int newcapcity = capacity() == 0 ? 4 : capacity() * 2;
        reserve(newcapcity);
    }
    *(_finish) = x;
    ++_finish;
}
  1. 尾删pop_back()
void pop_back()
{
    assert(_finish >= _start);
    --_finish;
}
  1. 在任意位置增加insert()
iterator insert(iterator pos, const T& x)
{
    assert(pos >= _start);
    assert(pos <= _finish);

    if (_finish == _endOfStorage)
    {
        //防止扩容的时候迭代器失效
        size_t old = pos - _start;
        reserve(capacity() == 0 ? 4 : capacity() * 2);
        pos = _start + old;
    }

    iterator end = _finish - 1;
    while (end >= pos)
    {
        *(end + 1) = *end;
        --end;
    }
    ++_finish;
    *pos = x;

    return pos;
}
  1. 在任意位置删除erase()
iterator erase(iterator pos)
{
    assert(pos >= _start);
    assert(pos < _finish);

    iterator cur = pos + 1;
    while (cur < _finish)
    {
        *(cur - 1) = *cur;
        cur++;
    }
    --_finish;
}

3.5 运算符重载

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

3.6构造/析构

//默认构造调用初始化列表,调用缺省值
vector()
{}

//有参构造
vector(int n, const T& value = T())
{
    resize(n);
}

//区间构造
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
    while (first < last)
    {
        push_back(*first);
        ++first;
    }
}

//拷贝构造
vector(const vector<T>& v)
{
    reserve(v.capacity());
    for (const auto& e : v)
    {
        push_back(e);
    }
}

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)
    {
        delete[] _start;
        _start = _finish = _endOfStorage = nullptr;
    }
}

4. 整体代码

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <assert.h>
using namespace std;

namespace qfw
{
    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;
        }

        // construct and destroy
        vector()
        {}

        vector(int n, const T& value = T())
        {
            resize(n);
        }

        template<class InputIterator>
        vector(InputIterator first, InputIterator last)
        {
            while (first < last)
            {
                push_back(*first);
                ++first;
            }
        }

        //拷贝构造
        vector(const vector<T>& v)
        {
            reserve(v.capacity());
            for (const auto& e : v)
            {
                push_back(e);
            }
        }

        //赋值
        vector<T>& operator= (vector<T> v)
        {
            swap(v);
            return *this;
        }

        ~vector()
        {
            if (_start)
            {
                delete[] _start;
                _start = _finish = _endOfStorage = nullptr;
            }
        }
        // capacity
        size_t size() const
        {
            return _finish - _start;
        }
        size_t capacity() const
        {
            return _endOfStorage - _start;
        }
        void reserve(size_t n)
        {
            if (n > capacity())
            {
                size_t old = size();
                T* tmp = new T[n];//开新的的空间
                //将数据拷贝到新的空间
                for (int i = 0; i < old; i++)
                {
                    tmp[i] = _start[i];
                }
                //删除旧的空间
                delete[] _start;
                //指向新新空间,更新数据
                _start = tmp;
                _finish = _start + old;
                _endOfStorage = _start + n;
            }
        }
        void resize(size_t n, const T& value = T())
        {
            if (n > size())
            {
                reserve(n);
                while (_finish < _start + n)
                {
                    *_finish = value;
                    ++_finish;
                }
            }
            else
            {
                _finish = _start + n;
            }
        }

        ///access///
        T& operator[](size_t pos)
        {
            return _start[pos];
        }
        const T& operator[](size_t pos)const
        {
            return _start[pos];
        }

        ///modify/
        void push_back(const T& x)
        {
            if (_finish == _endOfStorage)
            {
                int newcapcity = capacity() == 0 ? 4 : capacity() * 2;
                reserve(newcapcity);
            }
            *(_finish) = x;
            ++_finish;
        }
        void pop_back()
        {
            assert(_finish >= _start);
            --_finish;
        }
        void swap(vector<T>& v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endOfStorage, v._endOfStorage);
        }
        iterator insert(iterator pos, const T& x)
        {
            assert(pos >= _start);
            assert(pos <= _finish);

            if (_finish == _endOfStorage)
            {
                //防止扩容的时候迭代器失效
                size_t old = pos - _start;
                reserve(capacity() == 0 ? 4 : capacity() * 2);
                pos = _start + old;
            }

            iterator end = _finish - 1;
            while (end >= pos)
            {
                *(end + 1) = *end;
                --end;
            }
            ++_finish;
            *pos = x;

            return pos;
        }
        iterator erase(iterator pos)
        {
            assert(pos >= _start);
            assert(pos < _finish);

            iterator cur = pos + 1;
            while (cur < _finish)
            {
                *(cur - 1) = *cur;
                cur++;
            }
            --_finish;
        }
    private:
        iterator _start = nullptr; // 指向数据块的开始
        iterator _finish = nullptr; // 指向有效数据的尾
        iterator _endOfStorage = nullptr; // 指向存储容量的尾
    };
}

到了这里,关于STL之vector容器的介绍与模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】:STL源码剖析之vector类容器的底层模拟实现

    构造一个空vector size和capacity为0 将_start _finish _endofstorage 都置为空指针即可 传统写法 : 1). 新开辟一块和 v 同样容量的空间,更新 _start, _finish, _endofstorage 2). 将 v 中的数据拷贝到新开辟的空间中 注意 : 不要使用memcpy函数拷贝数据,如果数据是内置类型或浅拷贝的自定义类型

    2024年02月04日
    浏览(51)
  • [STL-list]介绍、与vector的对比、模拟实现的迭代器问题

     list的底层是 带头双向链表 结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。 与其他的序列式容器相比(array,vector,deque),list通常 在任意位置进行插入、移除元素的执行效率更好 list最大的缺陷是 不支持任意位

    2024年04月15日
    浏览(94)
  • 【STL】模拟实现vector(详解)

    2023年05月14日
    浏览(37)
  • 【STL】vector的模拟实现

    目录 前言 结构解析 构造析构 构造 默认构造 初始化成 n 个 val  以迭代器区间构造 拷贝构造 析构 运算符重载 赋值重载 下标访问 迭代器 const迭代器 容量操作 查看大小和容量 容量修改 数据修改 尾插尾删 指定位置插入和删除 insert erase 清空 判空 交换 源码 从vector开始就要开

    2024年02月06日
    浏览(66)
  • 【STL】 模拟实现简易 vector

    目录 1. 读源码 2. 框架搭建 3. vector 的迭代器 4. vector 的拷贝构造与赋值 拷贝构造 赋值 5. vector 的常见重要接口实现 operator[ ] 的实现 insert 接口的实现 erase 接口实现 pop_back 接口的实现 resize 接口实现 源码分享 写在最后: 想要自己实现一个 vector,读源码来理解他的实现是必不

    2024年02月16日
    浏览(35)
  • 【STL】:vector的模拟实现

    朋友们、伙计们,我们又见面了,本期来给大家解读一下有关vector的模拟实现,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏: C语言:从入门到精通 数据结构专栏: 数据结构 个  人  主  页 : stackY、 C + + 专 栏   : C++ Linux 专

    2024年02月06日
    浏览(97)
  • [STL] vector 模拟实现详解

    目录 一,准备工作 二,push_back   1, 关于引用 2. 参数const 的修饰  补充 三,迭代器实现 四,Pop_back 五,insert 1. 补充——迭代器失效 六, erase 七,构造函数  1. 迭代器构造  2. 其他构造 3. 拷贝构造  1) 传统写法 2)现代写法(提高函数复用性)  八,赋值符号重载 九,

    2024年02月16日
    浏览(39)
  • 【C++庖丁解牛】STL之vector容器的介绍及使用 | vector迭代器的使用 | vector空间增长问题

    🍁你好,我是 RO-BERRY 📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 vector的文档介绍 vector是表示可变大小数组的序列容器。 就像数组一样,vector也采用的连续存储空间来存

    2024年03月14日
    浏览(75)
  • 【C++ STL】vector模拟实现

    2023年05月17日
    浏览(50)
  • C++ STL vector 模拟实现

    ✅1主页:我的代码爱吃辣 📃2知识讲解:C++之STL 🔥3创作者:我的代码爱吃辣 ☂️4开发环境:Visual Studio 2022 💬5前言:上次我们已经数字会用了vector,这次我们对其底层更深一步挖掘,其中重点是,Vector中一些深浅拷贝问题。 目录 一.Vector模拟实现的整体框架 二. Vector的构

    2024年02月13日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包