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

相关推荐
诗书画唱2 分钟前
解决HTML/JS开发中的常见问题与实用资源
前端·javascript·html
Mintopia3 分钟前
🚀 Next.js 自建部署全家桶:Docker + PM2 + Nginx
前端·javascript·全栈
鹏多多6 分钟前
详解vue渲染函数render的使用
前端·javascript·vue.js
定栓10 分钟前
Typescript入门-JSDoc注释及tsconfig讲解
前端·javascript·typescript
AJi11 分钟前
EGL使用记录
前端·opengl
法欧特斯卡雷特15 分钟前
Kotlin 2.2.20 现已发布!下个版本的特性抢先看!
android·前端·后端
小意恩19 分钟前
el-table表头做过滤
前端·javascript·vue.js
小桥风满袖20 分钟前
极简三分钟ES6 - 迭代器Iterator
前端·javascript
小菜全20 分钟前
ElementUI 组件概览
前端·vue.js·elementui
JarvanMo31 分钟前
提升生产力:每个 iOS 开发者都应该知道的 10 个 Xcode 技巧
前端