vector的自实现(迭代器失效问题)与继承续讲

news2024/9/20 16:43:09

引子:在生活中,我们使用vector很频繁,我们是不是可以自己来实现一个呢?,其实也不难,我们在学过数据结构,就很easy啦!

As we all kowmn,vector基础有以下函数!

from my  perspective<实现代码

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

namespace My_vector
{
    template<class T>
    class vector
    {
    public:
        // Vector的迭代器是一个原生指针
        typedef T* iterator;//进行统一的命名
        iterator begin()
        {
            return _start;
        }
        iterator end()
        {
            return _finish;
        }

        typedef const T* const_iterator;
        const_iterator cbegin() const
        {
            return _start;
        }
        const_iterator cend() const
        {
            return _finish;
        }
        
        size_t capacity() const
        {
            return _end_of_storage - _start;
        }
        size_t size()  const
        {
            return _finish - _start;
        }

        void reserve(size_t n)
        {
            if (n > capacity())
            {
                size_t oldsize = size();
                T* tmp = new T[n];//创建临时变量,利用完后会进行析构
                if (_start)//进行拷贝数据
                {
                    for (size_t i = 0; i < oldsize; i++)
                    {
                        tmp[i] = _start[i];
                    }
                    delete[] _start;
                }
                _start = tmp;
                _finish = _start + oldsize;
                _end_of_storage = _start + n;
            }
        }
        void push_back(const T& x)
        {
            if (_finish == _end_of_storage)//进行扩容操作
            {
                size_t newcapacity = (_end_of_storage-_start)== 0 ? 4 :(_end_of_storage - _start)*2;
                reserve(newcapacity);
            }
            *_finish = x;
            _finish++;
        }
        void resize(size_t n, const T& value = T())//默认的升序的排序
        {
            if (n <= size())
            {
                _finish = _start+n;
            }
            else
            {
                for (int i = 0; i < (n - size()); i++)
                {
                    push_back(value);
                }
            }
        }
        void swap(vector<T>&v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_end_of_storage, v._end_of_storage);
        }
        vector() 
            : _start(nullptr), 
            _finish(nullptr), 
            _end_of_storage(nullptr)
        {}

        vector(int n, const T& value = T())
            : _start(nullptr),
            _finish(nullptr),
            _end_of_storage(nullptr)
        {
            reserve(n);
            for (int i = 0; i < n; i++)
            {
                push_back(value);
            }
        }

        template<class InputIterator>
        vector(InputIterator first=nullptr, InputIterator last=nullptr)
        {
            reserve(last - first);
            while (first != last)
            {
                 push_back(*first);
                 ++first;
            }
        }
        vector(const vector<T>& v)
            : _start(nullptr),
            _finish(nullptr),
            _end_of_storage(nullptr)
        {
            reserve(v.capacity());
            for (auto e : v)
            {
                push_back(e);
            }
        }
        // "=default"函数特性仅适用于类的特殊成员函数,且该特殊成员函数没有默认参数
        //
        // vector():default;

        vector<T>& operator=(vector<T> v)
        {
            swap(v);//交换后,不需要的会被析构掉!
            return *this;
        }

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

        T& operator[](size_t i)
        {
            assert(i < size());

            return _start[i];
        }

        const T& operator[](size_t i) const
        {
            assert(i < size());

            return _start[i];
        }
        void pop_back()
        {
            assert(size() > 0);

            --_finish;
        }

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

            iterator it = pos + 1;
            while (it != _finish)
            {
                *(it - 1) = *it;
                ++it;
            }

            --_finish;
        }
        //注意迭代器失效问题
        iterator insert(iterator pos, const T& x)
        {
            assert(pos >= _start);
            assert(pos <= _finish);

            if (_finish == _end_of_storage)
            {
                size_t len = pos - _start;

                size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
                reserve(newcapacity);

                pos = _start + len;
            }

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

            *pos = x;
            ++_finish;

            return pos;
        }
    private:
        iterator _start; // 指向数据块的开始
        iterator _finish; // 指向有效数据的尾
        iterator _end_of_storage; // 指向存储容量的尾
    };
    void text1()
    {
        vector<int>c;

        c.push_back(1);
        c.push_back(2);
        c.push_back(3);
        c.push_back(14);
        c.insert(c.begin() + 2, 29);
        c.insert(c.begin() + 3, 99);
        c.erase(c.begin());
        for (auto e : c)
        {
            cout << e << " ";
        }
    }

}

效果:

疑问+解答:

可不可以用输出流呢?答案是可以的!

template<typename T>
ostream& operator<<(ostream& out, const vector<T>& d)
{
    typename vector<T>::const_iterator cit = d.cbegin();

    while (cit != d.cend())
    {
        out << *cit << endl;
        ++cit;
    }
    //for (auto e : d)
    //{
    //    out << e << " ";
    //}
    return out;
}

迭代器失效问题

个人认为:失效情况一般发生在增容与缩容上

有以下几种情况

一,会引起其底层空间改变的操作,都有可能是迭代器失效,

比如:resize、reserve、insert、assign、 push_back等,也就是说vector底层原理旧空间被释放掉, 而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的 空间,而引起代码运行时崩溃。

解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新 赋值即可。

二,指定位置元素的删除操作--erase

删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代 器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是 没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效 了

也就是,原来的迭代器指向的位置变为了它的下一个。

三,与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效

继承

接上回所说!我们讲到继承的默认构造函数!那我们讲讲继承的分类与默认函数!

分类:

一,多层继承是从一个派生类派生出另一个派生类的过程。

二,多重继承是从两个或更多类派生出一个新类的过程

三,混合继承是多种类型继承的组合。

四,分层继承是从一个基类派生出两个或更多个类的过程。

继承的默认函数!

一,默认构造函数
  • 如果基类有一个默认构造函数(即无参数的构造函数),并且派生类没有显式地调用基类的构造函数,那么编译器会隐式地调用基类的默认构造函数。
  • 如果基类没有默认构造函数,但派生类没有显式地调用基类的任何构造函数,那么编译器会报错,因为它不知道如何初始化基类部分
  • 在派生类的构造函数的初始化列表中,可以显式地调用基类的构造函数。
  • 总结:不管子类,都会调用父类的!然后才会调用子类
二,c++继承中默认析构函数
  1. 自动生成:如果派生类没有定义自己的析构函数,编译器会为它生成一个默认析构函数。这个默认析构函数会隐式地调用基类的析构函数(如果存在的话)。

  2. 清理工作当派生类对象被销毁时,其析构函数首先被调用。派生类的析构函数体中通常包含释放派生类成员变量所占用的资源的代码。然后,析构函数会自动调用基类的析构函数,以便释放基类部分所占用的资源。这个过程会一直递归进行,直到最顶层的基类。

  3. 虚析构函数:在涉及多态的情况下(即基类指针或引用可能指向派生类对象时),基类应该声明一个虚析构函数(virtual destructor)。这是因为如果没有虚析构函数,当使用基类指针删除派生类对象时,只有基类的析构函数会被调用,派生类的析构函数不会被调用,这可能导致资源泄露和其他问题。声明虚析构函数可以确保在删除对象时,首先调用派生类的析构函数,然后再调用基类的析构函数。

  4. 删除或禁用默认析构函数:和构造函数一样,析构函数也可以被声明为= delete;来禁用它,或者由于其他原因而变得不可用(如被声明为私有)。如果派生类的析构函数被禁用或不可用,那么该派生类的对象就不能被销毁。

三,c++继承中默认拷贝构造函数

在继承的上下文中,派生类的拷贝构造函数需要特别小心处理,以确保基类部分也被正确地拷贝。

如果派生类没有显式定义拷贝构造函数,编译器会生成一个默认的拷贝构造函数。这个默认的拷贝构造函数会调用基类的拷贝构造函数(如果存在的话)来拷贝基类部分,并逐个成员地拷贝派生类自己的成员。

然而,在某些情况下,你可能需要自定义派生类的拷贝构造函数,以确保正确地拷贝派生类特有的数据成员或执行其他必要的操作。在自定义拷贝构造函数时,你应该显式地调用基类的拷贝构造函数,以确保基类部分也被正确地拷贝。

好了,让我们相遇在下一篇博客!持续分享,大派送!

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

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

相关文章

GMSB文章五:微生物组差异分析ANCOMBC-2

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 介绍 微生物的物种差异分析是一项关键的生物信息学任务&#xff0c;旨在识别不同生物群落或样本组…

k-NN 剪辑近邻法

本篇文章是博主在人工智能等领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在AI学习笔记&#…

基于halcon的眼在手外(Eye-to-Hand)标定

前言 上个月写了一个《基于halcon的眼在手上&#xff08;Eye-in-Hand&#xff09;标定》的文章&#xff0c;通过官方的示例代码进行了简单的叙述&#xff0c;想学习的小伙伴可以点击链接进行学习。之前博主认为眼在手上&#xff08;Eye-in-Hand&#xff09;的案例更多&#xff…

【Java笔记】Flyway数据库管理工具的基本原理

文章目录 1. 工作流程2. 版本号校验算法3. 锁机制3.1 为什么数据库管理工具需要锁3.2 flyway的锁机制 Reference 最近实习做的几个项目都用到了Flyway来做数据库的版本管理&#xff0c;顺便了解了下基本原理&#xff0c;做个记录。 详细的使用就不写了&#xff0c;网上教程很多…

【财经研究】并购重组的“不可能三角”

伴随着沪深IPO景气度下滑后&#xff0c;并购重组正受到市场的关注。 近期监管层正频频为并购重组发声 6月20日&#xff0c;证监会主席吴清在陆家嘴论坛上指出&#xff1a;“支持上市公司运用各种资本市场工具增强核心竞争力&#xff0c;特别是要发挥好资本市场并购重组主渠道作…

干涉阵型成图参数记录【robust】

robust 这个玩意经常忘记&#xff0c;就是取2的时候是更加显示大尺度的结构&#xff0c;取-2更加显示小尺度结果&#xff0c;一般取0就是正常就好了

高效同步的PWM升压DC/DC转换器 SD6201/SD6201-AF

SD6201是高效同步的PWM升压DC/DC转换器优化为介质提供高效的解决方案电力系统。这些设备在输入电压介于0.9V和4.4V之间&#xff0c;带有1.4MHz固定频率切换。这些功能通过允许使用小型、薄型电感器以及陶瓷电容器。自动PWM/PFM轻负载下的模式切换可节省电力提高了效率。电压在2…

IMU坐标系与自定义坐标系转化

1.首先示例图为例&#xff1a; 虚线黑色角度为IMU的坐标系&#xff1b;实线为自定义坐标系&#xff1b; 矫正&#xff1a;&#xff08;默认angleyaw为IMU采的数据角度&#xff09; angleyaw_pt angleyaw-25;if(-180<angleyaw&&angleyaw<-155) // 角度跳变问…

GuiLite C语言实现版本

简介 本项目是idea4good/GuiLite的C语言实现版本&#xff0c;基于2024-06-20节点的版本&#xff08;提交ID&#xff1a;e9c4b57&#xff09;。 本项目仓库&#xff1a;GuiLite_C 需求说明 作为芯片从业人员&#xff0c;国产芯片普遍资源有限&#xff08;ROM和RAM比较少-都是…

Str.format()方法

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 在Python2.6之后&#xff0c;提供了字符串的format()方法对字符串进行格式化操作。format()功能非常强大&#xff0c;格式也比较复杂&…

深度学习论文撰写实验对比分析时复现其它论文方法的问题

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

BERT论文略读

《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》 &#xff08;https://arxiv.org/abs/1810.04805&#xff09; 摘要&#xff1a;前人优秀工作仅用了单向信息且不能很好的应用到各类下游任务&#xff0c;本文提出一种基于Transformer的双…

如何理解AKM?

关于Wi-Fi的加密认证过程&#xff0c;我们前面已经讲解&#xff1a;WLAN数据加密机制_tls加密wifi-CSDN博客 今天我们来理解下AKM&#xff0c;AKM&#xff08;Authentication and Key Management&#xff09;在Wi-Fi安全中是指认证和密钥管理协议。它是用于确定Wi-Fi网络中的认…

【Linux】Linux下使用套接字进行网络编程

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 ​ 用于网络应用开…

揭秘数据合并的秘密:一文掌握一对一、多对一、多对多合并技巧与实战!

使用pd.merge()合并 类似 MySQL 中表和表直接的合并merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并每一列元素的顺序不要求一致1. 一对一合并 df1 = pd.DataFrame({"…

搜维尔科技:SenseGlove Nova2国内首款支持手掌心力回馈手套开售

《SenseGlove Nova 2》现正全球发行中! 搜维尔科技独家代理最新上市的 SenseGlove Nova 2 是世上首款&#xff0c;也是目前市面上唯一一款提供手掌力回馈的无缐VR力回馈手套&#xff0c;它结合了三种最先进的反馈技术&#xff0c;包括主动反馈、强力反馈及震动反馈&#xff0c…

k8s学习笔记(一)

configMap 一般用来存储配置信息 创建configMap 从文件中获取信息创建&#xff1a;kubectl create configmap my-config --from-file/tmp/k8s/user.txt 直接指定信息&#xff1a; kubectl create configmap my-config01 --from-literalkey1config1 --from-literalkey2confi…

小九首度回应与小水分手传闻揭秘

#小九首度回应&#xff01;与小水分手传闻揭秘#近日&#xff0c;泰国娱乐圈掀起了一股热议的狂潮&#xff01;传闻中的“金童玉女”组合——“小水”平采娜与“小九”NINE疑似分手的消息&#xff0c;如同巨石投入平静的湖面&#xff0c;激起了千层浪花。而在这股狂潮中&#xf…

CesiumJS【Basic】- #020 加载glb/gltf文件(Primitive方式)

文章目录 加载glb/gltf文件(Primitive方式)1 目标2 代码实现3 资源文件加载glb/gltf文件(Primitive方式) 1 目标 使用Primitive方式加载glb/gltf文件 2 代码实现 import * as Cesium from "cesium";const viewer = new Cesium.Viewer

x264 码率控制 VBV 算法原理:数学模型与数据流转

x264 码率控制 VBV 算法原理 关于 VBV原理的分析可以参考:x264 码率控制 VBV 原理。关于 VBV 算法的源码分析可以参考:x264 码率控制中实现 VBV 算法源码分析。VBV算法介绍 x264中的VBV(Video Buffering Verifier)算法是H.264编码标准的一部分,主要用于码率控制,确保视频…