C++STL专题 vector底层实现

news2024/11/26 14:50:32


目录

一, vector的手搓

1.构造函数

2. 拷贝构造的实现

3.析构函数

4.begin() end() 的实现

5.reserve的实现

6.size和capacity的实现

7.push_back的实现

8.pop_back的实现

9.empty的实现

10.insert的实现

11.erase的实现

12.resize的实现

13.clear的实现

14.swap的实现

14. []重载

15.=重载

16. Vector类中的private

二,源码


一, vector的手搓

Vector类的定义

template <class T>
class Vector
{
public:
    typedef T* iterator;
    typedef const T* const_iterator;

    Vector()
    {}



private:
    iterator _start = nullptr;//最开始
    iterator _finish = nullptr;//内容结尾(并不是容量的结尾)
    iterator _end_of_storage = nullptr;//容量结尾
};

1.构造函数

template<class InputIterator>
Vector(InputIterator first, InputIterator last)
{
    while (first != last)
    {
        Push_back(*first);
        first++;
    }
}

(1).在模板类中再定义模板类,使得能够插入不同容器的值。

2. 拷贝构造的实现

Vector(const Vector<T>& v)//拷贝构造
{
    for (auto& e : v)
    {
        Push_back(e);
    }
}

(1).直接使用范围for遍历一次即可。

3.析构函数

~Vector()
{
    if (_start)
    {
        delete[] _start;
        _start = _finish = _end_of_storage = nullptr;
    }
}

(1).如果_start不空的话,就使用delete[] 释放空间。并且置空。

 

4.begin() end() 的实现

iterator begin()
{
    return _start;
}

iterator end()
{
    return _finish;
}

const_iterator begin() const
{
    return _start;
}

const_iterator end() const
{
    return _finish;
}

(1).分为const修饰和不加const修饰,构成了函数重载,begin()返回起始_start即可,end()返回_finsih即可。

5.reserve的实现

void Reserve(size_t n)
{
    if (n > Capacity())
    {
        size_t oldsize = Size();
        T* tmp = new T[n];

        for (int i = 0; i < oldsize; i++) {
            tmp[i] = _start[i];
        }

        //memcpy(tmp, _start, Size() * sizeof(T));
        delete[] _start;

        _start = tmp;
        _finish = tmp + oldsize;
        _end_of_storage = tmp + n;
    }
}

(1).扩容函数,如果要求的空间大于当前的容量,就要扩容,首先存储当先数据个数Size()到oldsize,然后再开辟一个新空间,然后把_start中的全部数据拷贝到tmp中,然后再把_start释放空间,再将tmp赋值给_start,将_finish指向tmp+oldsize的位置。_end_of_storage指向tmp+n的位置。

6.size和capacity的实现

size_t Size()
{
    return _finish - _start;
}

size_t Capacity()
{
    return _end_of_storage - _start;
}

(1).Size为vector中数据个数,所以直接返回_finish(最后一个数据的地址)减start(第一个数据的地址)即可。

(2).Capacity为vector中容量大小,所以直接返回_end_of_storage(容量的最后一个地址)减start(第一个数据的地址)即可。

7.push_back的实现

void Push_back(const T& x)
{
    if (_finish == _end_of_storage) // 扩容
    {
        Reserve(Capacity() == 0 ? 4 : Capacity() * 2);
    }
    *_finish = x;
    ++_finish;
}

(1).push_back前要检查是否需要扩容,这里选择二倍扩容。

(2).直接将*_finish(元素的最后一个位置的下一个位置)赋值为x。再将_finish自加,使其移动到空位置,方便下次赋值。

8.pop_back的实现

void Pop_back()
{
    assert(!empty());
    --_finish;
}

(1).首先判断是否为空,如果为空就断言。

(2).直接将_finish自减即可。

9.empty的实现

bool empty()
{
    return _start == _finish;
}

(1).判断_start 和 _finish是否相等即可,如果相等就为空,否则为不空。

10.insert的实现

iterator insert(iterator pos, const T& x)
{
    assert(pos >= _start);
    assert(pos <= _finish);
    if (_finish == _end_of_storage) // 扩容
    {
        size_t len = pos - _start; // 解决迭代器失效
        Reserve(Capacity() == 0 ? 4 : Capacity() * 2);
        pos = _start + len; // 解决迭代器失效
    }

    iterator end = _finish - 1;
    while (end >= pos) // 迭代器失效问题已经扩容了,但是pos还是指向原来的旧空间 野指针
    {
        *(end + 1) = *end;
        end--;
    }
    *pos = x;
    ++_finish;

	return pos;
}

(1).大致思路为把要插入位置(pos)之后的全部向后移动一位,然后再将pos位置赋值为要插入的元素。

(2).要想插入,首先判断是否需要扩容。

(3).定义一个迭代器end,存储vector中最后一个元素的位置,然后循环判断(end >= pos),每次成立时,就把end+1处赋值为end的元素,然后将end自减。退出循环后,直接将*pos赋值为x并把_finish自加即可。

11.erase的实现

void erase(iterator pos)
{
    assert(pos >= _start);
    assert(pos <= _finish);
    iterator it = pos + 1;
    while (it != end())
    {
        *(it - 1) = *it;
        ++it;
    }
    --_finish;
}

(1).大致思路为将pos位置之后的全部元素都向前移动一个位置,最后将_finish自减即可。

12.resize的实现

void resize(size_t n, T val = T())
{
    // n<size
    // size<n<capacity
    // n>capaciity
    if (n < Size())
    {
        _finish = _start + n;
    }
    else
    {
        Reserve(n);
        while (_finish < _start + n)
        {
            *_finish = val;
            ++_finish;
        }
    }
}

(1).resize为对字符串大小做改变,当n<size时,就会对当前字符串缩减,其余情况为reserve。

13.clear的实现

void clear()
{
    _finish = _start;
}

(1).直接将_finish=_start即可。

14.swap的实现

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

(1).直接交换即可。

14. []重载

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

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

(1).由于_start为顺序表,所以直接返回顺序表的值即可。

15.=重载

//方法一:

Vector<T>& operator=(const Vector<T>& v)
{
    if (this != &v)
    {
        clear();
        Reverse(v.Size());
        for (auto& e : v)
        {
            Push_back(e);
        }
    }
    return *this;
}

//方法二:
 Vector<T>& operator=( vector<T> v)
 {
     swap(v);
     return *this;
 }

(1).有两种方法,第一种方法为先清空_start,然后再对_start重新扩容,扩容置与v相等,然后遍历v,把v中的元素按个插入_start。

(2).方法二:要进行传值传参,不能用传址传参,然后直接交换即可,这样_start就成了v了,由于v为传值传参,并不受影响。

16. Vector类中的private

private:
    iterator _start = nullptr;//缺省
    iterator _finish = nullptr;//缺省
    iterator _end_of_storage = nullptr;//缺省

二,源码

#pragma once
#include <iostream>
#include <vector>
#include <assert.h>
#include<algorithm>

namespace hhc
{
    template <class T>
    class Vector
    {
    public:
        typedef T* iterator;
        typedef const T* const_iterator;

        Vector()
        {}

        Vector(const Vector<T>& v)//拷贝构造
        {
            for (auto& e : v)
            {
                Push_back(e);
            }
        }

        ~Vector()
        {
            if (_start)
            {
                delete[] _start;
                _start = _finish = _end_of_storage = nullptr;
            }
        }

        iterator begin()
        {
            return _start;
        }

        iterator end()
        {
            return _finish;
        }

        const_iterator begin() const
        {
            return _start;
        }

        const_iterator end() const
        {
            return _finish;
        }

        void Reserve(size_t n)
        {
            if (n > Capacity())
            {
                size_t oldsize = Size();
                T* tmp = new T[n];

                for (int i = 0; i < oldsize; i++) {
                    tmp[i] = _start[i];
                }

                //memcpy(tmp, _start, Size() * sizeof(T));
                delete[] _start;

                _start = tmp;
                _finish = tmp + oldsize;
                _end_of_storage = tmp + n;
            }
        }

        size_t Size()
        {
            return _finish - _start;
        }

        size_t Capacity()
        {
            return _end_of_storage - _start;
        }

        void Push_back(const T& x)
        {
            if (_finish == _end_of_storage) // 扩容
            {
                Reserve(Capacity() == 0 ? 4 : Capacity() * 2);
            }
            *_finish = x;
            ++_finish;
        }

        bool empty()
        {
            return _start == _finish;
        }

        void Pop_back()
        {
            assert(!empty());
            --_finish;
        }

        void insert(iterator pos, const T& x)
        {
            assert(pos >= _start);
            assert(pos <= _finish);
            if (_finish == _end_of_storage) // 扩容
            {
                size_t len = pos - _start; // 解决迭代器失效
                Reserve(Capacity() == 0 ? 4 : Capacity() * 2);
                pos = _start + len; // 解决迭代器失效
            }

            iterator end = _finish - 1;
            while (end >= pos) // 迭代器失效问题已经扩容了,但是pos还是指向原来的旧空间 野指针
            {
                *(end + 1) = *end;
                end--;
            }
            *pos = x;
            ++_finish;
        }

        void erase(iterator pos)
        {
            assert(pos >= _start);
            assert(pos <= _finish);
            iterator it = pos + 1;
            while (it != end())
            {
                *(it - 1) = *it;
                ++it;
            }
            --_finish;
        }

        void resize(size_t n, T val = T())
        {
            // n<size
            // size<n<capacity
            // n>capaciity
            if (n < Size())
            {
                _finish = _start + n;
            }
            else
            {
                Reserve(n);
                while (_finish < _start + n)
                {
                    *_finish = val;
                    ++_finish;
                }
            }
        }

        void clear()
        {
            _finish = _start;
        }

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


        template<class InputIterator>
        Vector(InputIterator first, InputIterator last)
        {
            while (first != last)
            {
                Push_back(*first);
                first++;
            }
        }

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

        const T& operator[](size_t i) const
        {
            return _start[i];
        }
        //方法一:

        Vector<T>& operator=(const Vector<T>& v)
        {
            if (this != &v)
            {
                clear();
                Reverse(v.Size());
                for (auto& e : v)
                {
                    Push_back(e);
                }
            }
            return *this;
        }

        //方法二:
         Vector<T>& operator=( vector<T> v)
         {
             swap(v);
             return *this;
         }


    private:
        iterator _start = nullptr;
        iterator _finish = nullptr;
        iterator _end_of_storage = nullptr;
    };

    template <class Container>
    void print_Container(const Container& v)
    {
        // 没用实例化的类模板里面取东西,编译器不能区分const_iterator是类型还是静态成员变量
        // 编译器规定不能去没用实例化的模板里面取东西
        typename Container::const_iterator it = v.begin();
        auto itt = v.begin(); // 这样也行
        while (it != v.end())
        {
            std::cout << *it << ' ';
            *it++;
        }
        std::cout << std::endl;
        for (auto num : v)
        {
            std::cout << num << ' ';
        }
    }

}

本篇完

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

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

相关文章

Cadence23学习笔记(十七)

吴老师的网站里面有很多cadence的开源项目&#xff0c;可以用来学习&#xff1a; 全志 H3 SOC 官方参考设计 DD3 16bitX2 原理图及PCB – 吴川斌的博客 (mr-wu.cn) cadence设置显示实时的走线长度&#xff1a; 在allegro进行布线时可以实时显示当先布线的实际长度有助于pcb的…

Javascript——NaN有什么用法

简介 在 JavaScript 中&#xff0c;NaN&#xff08;Not a Number&#xff09;是一个特殊的值&#xff0c;用来表示非数字的结果&#xff0c;例如一个不合法的数学运算的结果。根据 IEEE 754 浮点数标准&#xff0c;NaN 不等于任何值&#xff0c;包括它自己。这意味着 NaN 是唯…

腾讯云服务器windows系统如何转linux系统

本人购买了腾讯云服务&#xff0c;进去后发现是windows系统的&#xff0c;有点郁闷&#xff08;使用不习惯&#xff09;&#xff0c;于是就去查查看看能不能将Windows系统转成linux系统&#xff0c;网上也有解决办法&#xff0c;但是貌似跟现在的腾讯云后台不一致&#xff0c;下…

dlid源码快速安装——百分百成功

前言 之前安装过一次dlib折腾了很久&#xff0c;最近子啊新的服务器上重新安装dlib这个包又遇到了一些问题&#xff0c;这里简单记录一下。 安装 我这里选择的是直接使用源码安装&#xff08;之前尝试过其他的安装方法&#xff0c;但是都失败了&#xff0c;索性这次就直接使用…

基于Java和Mysql的多人命题系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;B/S架构、SSM框架 工具&#xff1a;Eclipse开发工具 系统展示 首页 管理员界面 教师管理界面 学生…

OZON热销文具产品,OZON文具有哪些热销品

OZON平台上的热销文具产品种类繁多&#xff0c;这些产品不仅满足了消费者在日常学习、办公中的需求&#xff0c;还体现了市场的趋势和消费者的偏好。以下是一些OZON平台上的热销文具产品及其特点&#xff1a; OZON热销文具产品地址&#xff1a;D。DDqbt。COm/74rD Top1 蓝色…

揭秘!结构健康自动化监测:高效精准,为何远超传统人工监测?

人工检测是依靠目测检查或借助于便携式仪器测量得到的信息&#xff0c;但是随着整个行业的发展&#xff0c;传统的人工检测方法已经不能满足检测需求&#xff0c;从人工检测到自动化监测已是必然趋势。 a. 从检测方式看 人工检测需要耗费大量的精力&#xff0c;从摆放检测工具到…

机器学习算法———深度学习(常见的结构)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

【wiki知识库】07.用户管理前端模块的添加-前端部分

&#x1f34a; 编程有易不绕弯&#xff0c;成长之路不孤单&#xff01; 目录 &#x1f34a; 编程有易不绕弯&#xff0c;成长之路不孤单&#xff01; 一、今日目标 二、前端部分的改造 2.1 修改the-header文件 2.2 用户展示/admin/user组件添加 2.2.1 /admin/user代码如下…

杂谈c语言——3.内存对齐

先看两个例子&#xff1a; typedef struct S {int a;double b;char c; }S;typedef struct B {int a;char b;double c; }B;int main() {printf("S : %d\n", sizeof(S));printf("B : %d\n", sizeof(B));return 0; } 结果为&#xff1a; S:24; B:16&#xff…

【Qt】项目代码

main.cpp文件 argc&#xff1a;命令行参数个数。*argv[ ]&#xff1a;每一个命令行参数的内容。main的形参就是命令行参数。QApplication a(argc, argv) 编写一个Qt的图形化界面程序&#xff0c;一定需要QApplication对象。 widget w; 在创建项目的时候&#xff0c;勾选widg…

AI岗位平均月薪已经超过4.6万,程序员该如何抓住这个机遇?

前言 自从ChatGPT横空出世以来&#xff0c;市场上一直用“iPhone时刻”、“划时代”、“工业革命”等词汇来形容AI领域的飞速进展。如今&#xff0c;随着AI大模型的竞争日益激烈&#xff0c;这个领域正在以前所未有的速度向前发展。 AI大模型的革命性突破 OpenAI最新推出的G…

Linux--网络层IP

IP协议 IP协议&#xff0c;全称Internet Protocol&#xff08;互联网协议&#xff09;&#xff0c;是TCP/IP协议族中的核心协议之一&#xff0c;用于在互联网络上进行数据的传输。IP协议的主要功能是确保数据从一个网络节点&#xff08;如计算机、服务器、路由器等&#xff09…

【C++第11章】Vector

【C第11章】Vector vector介绍&#x1f9d0; vector是表示可变大小数组的序列容器&#xff0c;它类似于数组&#xff0c;但大小可以动态改变&#xff0c;并且大小会被容器自动处理。本质上说&#xff0c;vector使用动态分配数组来存储元素&#xff0c;为了减少扩容代价&#x…

音频剪辑软件哪个好用?音乐制作必备的6款音频剪辑工具

在这个充满声音的世界里&#xff0c;音乐和音频不仅仅是艺术表达的一种形式&#xff0c;更是情感的载体&#xff0c;是故事的讲述者。 你是否曾想过&#xff0c;那些令人动容的电影配乐、让人热血沸腾的电音节拍或是清晨唤醒你的温柔闹钟&#xff0c;是如何从一堆杂乱无章的声…

坐牢第二十三天 20240806(IO)

一.作业 1> 使用消息队列完成两个进程之间相互通信 A.c #include <myhead.h> // 要发送的消息类型 struct msgbuf {long mtype; /* message type, must be > 0 */char mtext[1024]; /* message data */ }; #define SIZE sizeof(struct msgbuf) - sizeof(l…

PEPM系统Cookie请求头远程代码执行漏洞复现 [附POC]

文章目录 PEPM系统Cookie请求头远程代码执行漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现PEPM系统Cookie请求头远程代码执行漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内的相关技术从事非法测试,…

mem0ai+ollama+qwen2搭建中文版运行环境

准备模型 支持function的qwen2模型 随便找了一个&#xff0c;也可以下载其他支持function的模型&#xff0c;或者自己下载模型文件搭建 ollama run sam4096/qwen2toolsembedder 模型 ollama run nomic-embed-text拉取mem0ai 源码&#xff0c;切换对应分支 git clone https…

【Foundation】(三)transformers之Model

文章目录 1、介绍1.1、 模型类型1.2、Model Head 2、模型加载3、模型调用3.1、不带Model Head的模型调用3.2、带Model Head的模型调用 4、模型微调实战4.1、导包4.2、加载数据4.3、创建数据集4.4、划分数据集4.5、创建加载器4.6、创建模型以及优化器4.7、模型训练4.8、模型评估…

Figma 替代品 Excalidraw 安装和使用教程

如今远程办公盛行&#xff0c;一个好用的在线白板工具对于团队协作至关重要。然而&#xff0c;市面上的大多数白板应用要么功能单一&#xff0c;要么操作复杂&#xff0c;难以满足用户的多样化需求。尤其是在进行头脑风暴、流程设计或产品原型绘制时&#xff0c;我们常常会遇到…