从零开始的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的情况,也可能会出现析构导致内容变成随机值无法正常使用。

相关推荐
freyazzr5 分钟前
Leetcode刷题 | Day60_图论06
数据结构·c++·算法·leetcode·图论
广药门徒9 分钟前
OpenMV IDE 的图像接收缓冲区原理
前端·人工智能·python
霸王蟹13 分钟前
常见面试题:Webpack的构建流程简单说一下。
前端·笔记·学习·webpack·node.js·vue
zhangpeng45554794016 分钟前
C++--综合应用-演讲比赛项目
开发语言·c++·算法
黄暄17 分钟前
Linux项目部署全攻略:从环境搭建到前后端部署实战
java·linux·运维·服务器·前端·后端·持续部署
啊我不会诶28 分钟前
CF每日4题(1300-1400)
开发语言·c++·算法
freyazzr38 分钟前
Leetcode刷题 | Day64_图论09_dijkstra算法
数据结构·c++·算法·leetcode·图论
island131442 分钟前
JAVA Web 期末速成
java·开发语言·前端
珊瑚里的鱼1 小时前
【滑动窗口】LeetCode 1004题解 | 最大连续1的个数 Ⅲ
开发语言·c++·笔记·算法·leetcode
小峰编程1 小时前
Python函数——万字详解
linux·运维·服务器·开发语言·前端·网络·python