从零开始的C++(十一)

vector的模拟实现:

1.构造函数:

复制代码
            vector()
            {

             }

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

            template<class InputIterator>

            vector(InputIterator first, InputIterator last)
            {  
                auto it = first;
                while (it != last)
                {
                    push_back(*it);
                    it++;
                }
            }
            void swap(iterator&v1,iterator&v2)
            {
                iterator ret = v1;
                v1 = v2;
                v2 = ret;
            }

            vector(const vector<T>& v)
            {
                vector<T>tmp(v.cbegin(), v.cend());
                swap(_start,tmp._start);
                swap(_finish, tmp._finish);
                swap(_endOfStorage, tmp._endOfStorage);
            }

       private:

           iterator _start = nullptr; // 指向数据块的开始

           iterator _finish = nullptr; // 指向有效数据的尾

           iterator _endOfStorage = nullptr; // 指向存储容量的尾

对象的成员使用了参数列表,防止随机值引发异常。同时,对于传同类型对象的构造函数,复用了传迭代器的构造函数创建临时对象,然后交换this所指对象和临时对象的成员的值,防止浅拷贝,并且利用临时变量销毁原本this对象的成员的内容。

2.赋值重载:

复制代码
     vector<T>& operator= (vector<T> v)
            {
                swap(_start, v._start);
                swap(_finish, v._finish);
                swap(_endOfStorage, v._endOfStorage);

                return *this;
             }

赋值重载的原理和拷贝构造类似,都是用临时对象交换赋值,此处不用创建临时对象的原因是在实参到形参的过程已经进行了拷贝构造,即此处形参就是临时对象,所以直接交换即可。

3.插入和删除

复制代码
  void push_back(const T& x)
            {
                if (size() == capacity())
                {
                    reserve(size() * 2+1);
                }
                *(_finish) = x;
                _finish++;
            }
           
            void pop_back()
            {
                assert(size() > 0);
                _finish--;
            }

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

            iterator insert(iterator pos, const T& x)
            {   
                assert(pos-_start <= size());
                assert(pos - _start>= 0);
                if (size() == capacity())
                {  
                    int sz = pos - _start;
                    reserve(size() * 2+1);
                    pos = _start + sz;
                }

                auto it = _finish-1;
                while (it >= pos)
                {
                    *(it + 1) = *it;
                    it--;
                }
                *pos = x;

                _finish++;
                return pos;
            }

            iterator erase(iterator pos)
            {   
                assert(pos-_start >= 0);
                assert(pos-_start < size());
                auto it = pos+1;
                while (it != _finish)
                {
                    *(it - 1) = *(it);
                    it++;
                }
                --_finish;
                   
                return pos;
             }

需要注意的是,insert和erase都可能会造成迭代器失效(即迭代器使用结果可能未定义或无法使用)。同时也需要注意判断插入、删除是否合理(是否越界等)。

4.扩容

复制代码
            void reserve(size_t n)
            {
                if (n >capacity())
                {    
                    int sz = size();
                    iterator tmp = new T[n];
                    if (_start!=nullptr)
                    {
                        //值拷贝
                        for (int i = 0; i < sz; i++)
                        {
                            tmp[i] = _start[i];
                        }
                    }
                    delete[]_start;
                    //更新
                    _start = tmp;
                    _endOfStorage = _start + n;
                    _finish = _start + sz;
                }
            }

            void resize(size_t n, const T& value = T())
            {
                if (n <=size())
                {
                    _finish = _start + n;
                }
                else
                {
                    reserve(n);
                    while (size() < n)
                    {
                        push_back(value);
                    }

                }




            }

扩容应注意是深拷贝,因为成员可能是自定义类型,有自己的析构函数,如果是浅拷贝可能会出现二次delete的情况,也可能会出现析构导致内容变成随机值无法正常使用。

相关推荐
晴天1613 小时前
多个 VS Code 项目会导致 Chrome 和 Electron 应用一起卡住?-Day30
前端·chrome·electron
Escalating_xu13 小时前
【C++入门基础(下)】默认参数、函数重载、引用、inline 与 nullptr
android·c++·redis
艾莉丝努力练剑13 小时前
【AI大模型接入SDK】Provider分析与实现
c++·人工智能·学习·面试·大模型·llm
BigTopOne19 小时前
【WebRtc】DTLS-SRTP 加密完整流程详解
前端
陈随易19 小时前
pm2 替代品,nodejs&bun 线上部署必备工具
前端·后端·程序员
单线程_0119 小时前
从案例分析 Vue3 Tokenizer 源码一
前端·javascript·vue.js
BigTopOne19 小时前
【WebRtc】-ICE Candidate 与 STUN/TURN 原理详解
前端
l12586519 小时前
# LangGraph Memory机制深度解析:短期记忆与长期记忆的工程实践
前端·人工智能·python·langchain·bootstrap
码视野20 小时前
基于 Spring Boot + Vue3 的【大学英语四六级 (CET-4/6) 作文智能评分与句式润色系统】设计与实现(含PRD/三端高保真源码/大屏)
java·前端·人工智能·spring boot·后端·vue3
大模型码小白20 小时前
AI 对话流性能调优:万级消息的虚拟滚动落地
java·大数据·前端·javascript·人工智能·算法·机器学习