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

相关推荐
鲨鱼吃橘子13 分钟前
【C++融会贯通】哈希表的使用
c语言·开发语言·数据结构·c++·链表·哈希算法·散列表
贩卖纯净水.14 分钟前
网站部署及CSS剩余模块
前端·css
誓约酱16 分钟前
Linux系统常用指令
linux·运维·服务器·c++
Justinc.23 分钟前
CSS3_BFC(十二)
前端·css·css3
刺客-Andy28 分钟前
React第四节 组件的三大属性之state
前端·javascript·react.js
黄毛火烧雪下30 分钟前
React 表单Form 中的 useWatch
前端·javascript·react.js
爱健身的小刘同学1 小时前
钉钉免登录接口
前端·javascript·钉钉
啵咿傲1 小时前
跨域相关的一些问题 ✅
前端
命运之光1 小时前
生日主题的烟花特效HTML,CSS,JS
前端·javascript·css
Heisenberg~1 小时前
详解C++类与对象(三)
c++