STL之vector(讲解迭代器失效,拷贝构造函数等现代版写法)

news2025/2/25 15:10:15

还是老规矩,直接上代码:

#pragma once
#include "riterator.hpp"
#include <iostream>
#include <assert.h>
#include <set>
#include <map>
using namespace std;
namespace cc
{
    template<class T>
    class vector
    {
     public:
        typedef T* iterator;
        typedef const T* const_iterator;
        vector()
            : _start(new T[4])
            , _finish(_start)
            , _end_of_strag(_start+4)
        {}
        template<class Iterator>
        vector(Iterator begin,Iterator end)
            : _start(new T[4])
            , _finish(_start)
            , _end_of_strag(_start+4)
        {
            //同样,这里最好不要用memcpy等函数(涉及深浅拷贝问题)
            while(begin!=end)
            {
                push_back(*begin);
                begin++;
            }
        }
        vector(const vector<T>& d)
            : _start(nullptr)
            , _finish(nullptr)
            , _end_of_strag(nullptr)
        {
            vector<T> tem(d.begin(),d.end());
            swap(tem);
        }
        ~vector()
        {
            delete[] _start;
            _start=_finish=_end_of_strag=nullptr;
        }
        vector<T>& operator=(vector<T> d)
        {
            swap(d);
            return *this;
        }
        void swap(vector<T>& d)
        {
            std::swap(_start,d._start);
            std::swap(_finish,d._finish);
            std::swap(_end_of_strag,d._end_of_strag);
        }
        iterator begin()
        {
            return _start;
        }
        iterator end()
        {
            return _finish;
        }
        const_iterator begin()const
        {
            return _start;
        }
        const_iterator end()const
        {
            return _finish;
        }
        size_t size()const
        {
            return _finish-_start;
        }
        size_t capacity()const
        {
            return _end_of_strag-_start;
        }
        T& operator[](size_t x)const
        {
            assert(x<size());
            return _start[x];
        }
        void resize(size_t n,const T& x=T())
        {
            _finish=_start+n;
            for(size_t i=0;i<n;i++)
                _start[i]=x;
        }
        void reserve(size_t n)
        {
            if(n>size())
            {
                iterator tem=new T[n];
                //这里最好不要用memcpy等函数(涉及深浅拷贝问题)
                for(size_t i=0;i<size();i++)
                    tem[i]=_start[i];
                size_t ret=_finish-_start;
                delete[] _start;
                _start=tem;
                _end_of_strag=_start+n;
                _finish=_start+ret;
            }
        }
        void push_back(const T& x)
        {
            if(size()==capacity())
                reserve(2*capacity());
            _start[_finish-_start]=x;
            _finish++;
        }        
     private:
        iterator _start;
        iterator _finish;
        iterator _end_of_strag;  
    };
}

很简单的一个容器,其实 本质原理就是类似于顺序表,在这里我并没有实现所有的功能,但是主要的功能都已经实现,顺序表我想大家应该都是比较熟悉的,所以这里就不讲实现的原理了,来说说这里最主要的一个问题。

vector最主要的问题是什么呢?其实就是深浅拷贝和迭代器的失效。

1.深浅拷贝的问题

这个很容易就写错了,哪怕拷贝构造函数等写的是深拷贝,但是如果再reserve这个函数内部一不注意就会出现浅拷贝的问题,注释中已经说明,这里不再多说,这个还是比较简单的。如果不知道自己实现的vector是否完成深拷贝,可以自己建造一个二维数组来试试

2.迭代器失效

迭代器失效在vector中有大两种:分别是插入,删除

插入导致迭代器失效:插入其实又有两种迭代器失效的可能,一种是插入的时候,需要扩容,此时如果一不小心就会到直接迭代器直接失效,其次就是在任意地方插入的时候,会导致迭代器失效的可能。

扩容导致迭代器失效原理:

我们可以看看下面的代码:

     //正确版
        // void reserve(size_t n)
        // {
        //     if(n>size())
        //     {
        //         iterator tem=new T[n];
        //         //这里最好不要用memcpy等函数(涉及深浅拷贝问题)
        //         for(size_t i=0;i<size();i++)
        //             tem[i]=_start[i];
        //         size_t ret=_finish-_start;
        //         delete[] _start;
        //         _start=tem;
        //         _end_of_strag=_start+n;
        //         _finish=_start+ret;
        //     }
        // }
        //错误版
        void reserve(size_t n)
        {
            if(n>size())
            {
                iterator tem=new T[n];
                for(size_t i=0;i<size();i++)
                    tem[i]=_start[i];
                delete[] _start;
                _start=tem;
                //经典错误出现的地方
                _finish=_start+size();
                _end_of_strag=_start+n;
            }
        }

为什么说这里有错误呢?两个看起来其实感觉也差不多,但为什么下面的是错误的呢?其实很好理解,因为在这里你的_finish=_start+size(),这里是不能加size()的,因为size的内部实现返回的是__finish-_start,但是此时的_start指向的是tem的空间,并且把原来的空间已经给释放了,所以此时会出现问题。

其次就是任意位置插入会导致迭代器失效原理:如下图:

 我们可以看到的是,我在3这里插入了7,把所有的数后移了一位,但是,我们可以看到的是,此时原本3这个位置的数变成了7,但是迭代器的位置其实没有变,所以此时你如果不更新迭代器的话,就到导致迭代器的失效。

删除导致迭代器的失效:

原理其实和插入差不多,都是原本位置上的数改变,而迭代器的位置没有改变,所以此时要更新迭代器,原理和插入导致的迭代器失效其实是一样的。大家可以仔细想想

还有就是拷贝构造和赋值运算符的重载的现代版写法,其实个人建议的是,如果理解不了现代版的写法,可以按照深拷贝的思路来慢慢写,现代版的实现只不过是代码比较简洁而已,不过还是看个人喜好了,现代版的实现提高了成员函数的耦合性(个人认为不好的一点),如果出现错误的,维修成本比较大,而原始的写法就没有这种问题。

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

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

相关文章

智安网络|监控与响应机制:建立有效的数据安全治理,保障数据安全

在当今数字化时代&#xff0c;数据安全治理对于保护组织的敏感信息和用户隐私至关重要。制定一个有效的数据安全治理策略能够明确组织对数据安全的重视&#xff0c;并确保数据得到适当的管理和保护。 1.确定数据安全治理的目标和范围 首先&#xff0c;组织需要明确数据安全治理…

蓝蓝设计ui设计公司作品--泛亚高科-光伏电站控制系统界面设计

泛亚高科(北京)科技有限公司&#xff08;以下简称“泛亚高科”&#xff09;&#xff0c;一个以实时监控、高精度数值计算为基础的科技公司&#xff0c; 自成立以来&#xff0c;组成了以博士、硕士为核心的技术团队&#xff0c;整合了华北电力大学等高校资源&#xff0c;凭借在电…

SQL注入读写文件

文章目录 条件利用SQL注入漏洞读取hosts文件查看文件读写权限安全选项允许导入导出读取hosts文件 利用SQL注入漏洞写入一句话木马&#xff0c;并用蚁剑连接webshell写入文件 条件 SQL注入有直接SQL注入&#xff0c;也有文件读写时的注入&#xff0c;后者的主要 目的在于获取web…

Android 13 - Media框架(6)- NuPlayer::Source

Source 在播放器中起着拉流&#xff08;Streaming&#xff09;和解复用&#xff08;demux&#xff09;的作用&#xff0c;Source 设计的好坏直接影响到播放器的基础功能&#xff0c;我们这一节将会了解 NuPlayer 中的通用 Source&#xff08;GenericSource&#xff09;关注本地…

Java后端面试题——Mysql篇

在Mysql中&#xff0c;如何定位慢查询呢&#xff1f; 表象&#xff1a;页面加载过慢、接口压测响应时间过长&#xff08;超过1s&#xff09; 原因&#xff1a;聚合查询 多表查询 表数据量过大查询 深度分页查询 方案&#xff1a;MySQL自带慢日志 需要在MySQL的配置文件&…

动捕设备之惯性动作捕捉,为何是数字人活动首选的动捕设备?

动捕设备是一种用于捕捉、记录和分析运动的设备&#xff0c;动捕设备可以实时追踪和记录人体的运动轨迹&#xff0c;并将这些动作捕捉数据传输到计算机上&#xff0c;赋予数字人身体姿态。而其中基于惯性动作捕捉技术的动捕设备VDSuit Full&#xff0c;是通过传感器实时测量人体…

【Hello Network】DNS协议 NAT技术 代理服务器

本篇博客简介&#xff1a;介绍DNS协议 NAT技术和代理服务器 网络各协议补充 DNSDNS背景DNS介绍DNS总结域名简介 NAT技术NAT技术背景NAT IP转换过程NAPTNAT技术缺陷NAT和代理服务器 网络协议总结应用层传输层网络层数据链路层 DNS DNS是一整套从域名映射到IP的系统 DNS背景 为…

【产品应用】一体化无刷电机在无泵罐装中的应用

随着科技的不断发展&#xff0c;电动化和智能化成为现代工业发展的两大趋势。在液体灌装领域&#xff0c;无泵罐装技术逐渐受到广泛关注。这种技术取消了传统的泵送系统&#xff0c;通过一体化无刷电机的应用&#xff0c;实现了更为高效、精确的灌装过程。本文将详细介绍一体化…

ICS PA1

ICS PA1 init.shmake 编译加速ISA计算机是个状态机程序是个状态机准备第一个客户程序parse_argsinit_randinit_loginit_meminit_isa load_img剩余的初始化工作运行第一个客户程序调试&#xff1a;零断点TUI 基础设施单步执行打印寄存器状态扫描内存 表达式求值词法分析递归求值…

Qt 雷达模拟仿真工具3.0

Qt 雷达模拟仿真工具3.0 文章目录 Qt 雷达模拟仿真工具3.0ChangeLog效果图Qt交流群 ChangeLog 原有功能1.0版本原有功能2.0版本增加百度在线地图;增加百度离线地图&#xff1b;增加地图街道图卫星图切换&#xff1b;增加地图缩放与雷达图距离联动&#xff1b;增加地图定位&…

icon图标一键制作,这个免费在线工具超好用!

图标设计看似微小,实则意义非凡。它能直观地表达抽象概念,减轻用户认知负担。设计师通过改变图标,可打造界面独特视觉风格。图标种类繁多,如平面、线条、玻璃、3D等。应用广泛,因此在线制作图标的设计工具备受设计师青睐。今天就来看看获取免费图标素材和快速在线制作图标的技巧…

CTFshow——web入门——反序列化web254-web278 详细Writeup

前言 在做题之前先简要总结一下知识点 private变量会被序列化为&#xff1a;\x00类名\x00变量名 protected变量会被序列化为: \x00\*\x00变量名 public变量会被序列化为&#xff1a;变量名__sleep() &#xff1a;//在对象被序列化之前运行__wakeup() //将在反序列化之后立即…

DIFFEDIT-图像编辑论文解读

文章目录 摘要算法Step1&#xff1a;计算编辑maskStep2&#xff1a;编码Step3&#xff1a;使用mask引导进行解码理论分析&#xff1a; 实验数据集&#xff1a;扩散模型&#xff1a;ImageNet数据集上实验消融实验IMAGEN数据集上实验COCO数据集上实验 结论 论文&#xff1a; 《D…

abap table control控制屏幕字段显示/隐藏

需求&#xff1a;隐藏TABEL CONTROL的某一列或者多列&#xff0c;其实针对这样子的需求&#xff0c;我们最常想到的就是通过设置字段属性为ACTIVE或INVISIBLE&#xff0c;经过测试&#xff0c;发现&#xff0c;此方法无效。 解决方法&#xff1a;通过CODING修改tabctrl-cols下…

Delphi 11.3 FMX 多设备平台中使用 TGrid 实现类似 TDBGrid 的效果

Delphi Firemonkey 中 TDBGrid 这个控件已经没有了。如何实现类似这个效果呢。其实可以用TGrid 来实现。以下用 11.3 来讲解。 查询里面用到的 connection 和 query 等控件那些一般的数据库用法&#xff0c;就不做过多描述了。请参考其他资料。 方法一.通过界面配置来实现 在…

SocketTools.NET 11.0.2148.1554 Crack

添加新功能以简化使用 URL 建立 TCP 连接的过程。 2023 年 8 月 23 日 - 12:35新版本 特征 添加了“HttpGetTextEx”函数&#xff0c;该函数在返回字符串缓冲区中的文本内容时提供附加选项。添加了对“FileTransfer”.NET 类和 ActiveX 控件中的“GetText”和“PutText”方法的…

尚硅谷大数据项目《在线教育之离线数仓》笔记004

视频地址&#xff1a;尚硅谷大数据项目《在线教育之离线数仓》_哔哩哔哩_bilibili 目录 第9章 数仓开发之DWD层 P049 P050 P051 P052 P053 P054 P055 P056 P057 P058 P059 P060 P061 P062 P063 P064 P065 P066 P067 P068 P069 P070 第9章 数仓开发之DWD…

java学习网站_Java程序员必看的学习网站

哔哩哔哩 B 站动力节点官方视频 https://space.bilibili.com/76542346?spm_id_from333.337.0.0 超多视频免费白嫖 专注 java 培训的动力节点 毕业学员业内高薪就业&#xff0c;逐渐得到了业界广大的好评&#xff0c;被业界誉为 “口口相传的 Java 黄埔军校 “。 网址&#x…

开机自启CPU设置定频

sudo apt-get install expect sudo apt-get install cpufrequtils具体步骤如下&#xff1a; 安装 cpufrequtils 工具 ⚫ sudo apt-get install cpufrequtils ⚫ 需要联网下载修改配置文件 ⚫ sudo vi /etc/init.d/cpufrequtils ⚫ 将 GOVERNOR“ondemand” 改为&#xff1a; &g…

Java 四种访问控制权限

1.背景&#xff1a; 针对java的类成员访问控制权限理解 2.Java有四种访问控制权限&#xff1a; private&#xff0c;protected&#xff0c;public&#xff0c;default 他们的具体访问权限都是什么呢&#xff1f;用例子来分析一下&#xff1a; 这里要分几个情景&#xff1a;内…