C++ - vector简单模拟实现

目录

一、整体框架

二、构造和析构函数

1.无参构造

2.迭代器区间构造

3.拷贝构造

4.赋值

5.析构

三、大小和容量相关函数

1.大小和容量

2.reserve

3.resize

四、插入和删除

1.尾插

2.尾删

3.插入

4.删除


一、整体框架

    template<class T>
    class vector
    {
    public:
        // Vector的迭代器是一个原生指针
        typedef T* iterator;
        typedef const T* const_iterator;
        iterator begin();
        iterator end();
        const_iterator cbegin() const;
        const_iterator cend() const;
        // construct and destroy
        vector();
        vector(int n, const T& value = T());

        template<class InputIterator>
        vector(InputIterator first, InputIterator last);
        vector(const vector<T>& v);
        vector<T>& operator= (vector<T> v);
        ~vector();
        // capacity
        size_t size() const;
        size_t capacity() const;
        void reserve(size_t n);
        void resize(size_t n, const T& value = T());
        ///access///
        T& operator[](size_t pos);
        const T& operator[](size_t pos) const;
        ///modify/
        void push_back(const T& x);
        void pop_back();
        void swap(vector<T>& v);
        iterator insert(iterator pos, const T& x);
        iterator erase(iterator pos);
    private:
        iterator _start; // 指向数据块的开始
        iterator _finish; // 指向有效数据的尾
        iterator _endOfStorage; // 指向存储容量的尾
    };

二、构造和析构函数

1.无参构造

        将三个指针置空即可。

        vector()
            : _start(nullptr)
            , _finish(nullptr)
            , _endOfStorage(nullptr)
        {}

2.迭代器区间构造

        复用尾插函数,遍历迭代器范围。

        template<class InputIterator>
        vector(InputIterator first, InputIterator last)
            :_start(nullptr)
            , _finish(nullptr)
            , _endOfStorage(nullptr)
        {
            for (InputIterator it = first; it != last; it++)
            {
                push_back(*it);
            }
        }

3.拷贝构造

        利用迭代器区间构造临时的变量,与临时变量交换即可完成拷贝构造。也可以重新开空间,再进行内容的拷贝,但明显以下写法更好。

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

        交换函数内容如下,交换两个实例中的指针内容。

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

4.赋值

        赋值可复用参数传递中的拷贝构造,交换内部的指针即可完成赋值。

        vector<T>& operator= (vector<T> v)
        {
            swap(v);
            return *this;
        }

5.析构

        释放空间,指针置空。

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

三、大小和容量相关函数

1.大小和容量

        返回大小或容量,利用指针相减即可。

        size_t size() const
        {
            return _finish - _start;
        }
        size_t capacity() const
        {
            return _endOfStorage - _start;
        }

2.reserve

        传入参数大于当前容量就会增容,不大于当前容量不会操作。

        由于增容需要开辟新的空间,原来的指针指向原来的空间,因此需要提前记录指针的相对位置,保证新空间的指针正确。同时在旧的内容拷贝上不要使用memcopy浅拷贝,否则在容器存放内置类型的数据时会导致多次析构出错。

        void reserve(size_t n)
        {
            if (n > capacity())
            {
                size_t size = _finish - _start;
                T* temp = new T[n];
                if (_start)
                {
                    for (int i = 0; i < size; i++)
                    {
                        temp[i] = _start[i];
                    }
                    delete[] _start;
                }
                _start = temp;
                _finish = _start + size;
                _endOfStorage = _start + n;
            }
        }

3.resize

        传入参数大于当前数据个数,对原有数据不改变,多出来的部分会初始化。如果大于当前容量,则先增容再初始化。小于当前数据个数,则会对数据进行截断。

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

四、插入和删除

1.尾插

        使用_finish指针操作即可,再扩容时如果容量为0,应给一个起始容量。

        void push_back(const T& x)
        {
            if (_finish == _endOfStorage)
            {
                reserve(capacity() == 0 ? 4 : capacity() * 2);
            }
            *_finish = x;
            _finish++;
        }

2.尾删

        需要保证不会在容器为空的情况下尾删。

        void pop_back()
        {
            assert(_finish > _start);
            _finish--;
        }

3.插入

        利用指针,移位数据,再将新数据插入。要考虑移位的方向会不会数据的覆盖,导致数据丢失。

        iterator insert(iterator pos, const T& x)
        {
            assert(pos >= _start);
            assert(pos <= _finish);
            if (_finish == _endOfStorage)
            {
                size_t sz = pos - _start;
                reserve(capacity() == 0 ? 4 : capacity() * 2);
                pos = _start + sz;
            }
            iterator it = _finish - 1;
            while (it != pos)
            {
                *(it + 1) = *it;
                it--;
            }
            *pos = x;
            _finish++;
            return pos;
        }

4.删除

        同上,用指针对数据移位,覆盖删除的位置。

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值