【vector模拟实现】

vector模拟实现

vector相关函数实现大纲

namespace yang
{
    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; // 指向存储容量的尾
    };

}

construct and destroy

  1. 要实现的构造函数

  2. 默认构造

    构造一个空的容器,没有任何元素
    
            vector()
            {
                _start = nullptr;
                _finish = nullptr;
                _endOfStorage = nullptr;
            }
    
  3. n个元素构造

    用n个元素构造一个容器,每个元素都是val
    
            vector(int n, const T& value = T())
                :_start(nullptr)
                ,_finish(nullptr)
                ,_endOfStorage(nullptr)
            {
                reserve(n);
                for (int i = 0; i < n; ++i)
                {
                    push_back(value);
                }
            }
    

    但是这个时候会遇到一个问题,就是如果我们调用vector
    v1(10,1)时,这个时候运行就会报错"非法的间接寻址",会调用迭代器区间构造函数,这个是因为模版会调用更符合的。如果这个时候我们想用这个模版,就要想这样调用vector
    v1(10u,1);

  4. 迭代器区间构造

     	这里需要传一个模版,因为迭代器区间构造的区间可能是其他不确定容器的区间。
    
            template<class InputIterator>
            vector(InputIterator first, InputIterator last)
                :_start(nullptr)
                , _finish(nullptr)
                , _endOfStorage(nullptr)
            {
                while (first != last)
                {
                    push_back(*first);
                    ++first;
                }
            }
    
  5. 拷贝构造函数
    1. 传统写法
    即开辟一块与容器相同的空间,然后将容器中的值一个一个拷贝过来.

       vector(const vector<T>& v)
           :_start(nullptr)
           , _finish(nullptr)
           , _endOfStorage(nullptr)
       {
           _start = new T[v.capacity];
           for (int i = 0; i < v.size(); ++i)
           {
               _start[i] = v[i];
           }
           _finish = _start + v.size();
           _endOfStorage = _start + v.capacity();
       }
    
    1. 现代写法

    使用范围for(或是其他遍历方式)对容器v进行遍历,在遍历过程中将容器v中存储的数据一个个尾插过来即可。
    这里的遍历的e就是v的每一个数据的拷贝,相当于调用v类型的拷贝构造(深拷贝).

            vector(const vector<T>& v)
                :_start(nullptr)
                , _finish(nullptr)
                , _endOfStorage(nullptr)
            {
                reserve(v.capacity());
                for (auto e : v)
                {
                    push_back(e);
                }
            }
    
  6. 赋值运算符重载函数

    1. 传统写法

    :首先判断是否是给自己赋值,若是给自己赋值则无需进行操作。若不是给自己赋值,则先开辟一块和容器v大小相同的空间,然后将容器v当中的数据一个个拷贝过来,最后更新_finish和_endofstorage的值即可。

            vector<T>& operator= (vector<T>& v)
            {
                if (this != &v)
                {
                    delete _start;
                    _start = new T[v.capacity()];
                    for (int i = 0; i < v.size(); ++i)
                    {
                        _start[i] = v[i];
                    }
                    _finish = _start + v.size();
                    _endOfStorage = _start + v.capacity();
                }
                return *this;
            }
    
    1. 现代写法

    :会直接调用参数的 拷贝构造(传值传参要调用拷贝构造)

            vector<T>& operator= (vector<T> v)
            {
                swap(v);
                return *this;
            }
    
  7. 析构函数

            ~vector()
            {
            //这里记得配套使用
                delete[] _start;
                _start = nullptr;
                _finish = nullptr;
                _endOfStorage = nullptr;
            }
    

迭代器相关函数

>         // Vector的迭代器是一个原生指针
	        typedef T* iterator;
	        typedef const T* const_iterator;

普通迭代器和const迭代器

 iterator begin()
 {
     return _start;
 }
 iterator end()
 {
     return _finish;
 }

 const_iterator cbegin() const
 {
     return _start;
 }
 const_iterator cend() const
 {
     return _finish;
 }

加入cosnt迭代器的目的是为了保证const对象调用该函数时只能进行对数据读操作.

capcity相关函数

size和capacity

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

resize和reserve

  1. reserve
    reserve官方描述
    对reserve的返回值的解释
 void reserve(size_t n)
 {
     if (n > capacity())
     {
         int sz = size();//有效个数
         T* tmp = new T[n];
         if (_start)
         {
             for (int i = 0; i < sz; ++i) {
                 tmp[i] = _start[i];
             }
         }
         delete[] _start;//释放该旧空间
         _start = tmp;
         _finish = _start + sz;
         _endOfStorage = _start + n;
     }
 }

假设模拟实现的vector中的reserve接口中,使用memcpy进行的拷贝,一下代码会发生什么问题呢?

  • 1.memcpy是内存的二进制格式拷贝,将一段内存空间中内存原封不动的拷贝到另外一段内存空间中。
    2.如果拷贝的是内置类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。

对用memcpy时的简易图示
结论:如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy时浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。
2. resize
对resize的解释

        void resize(size_t n, const T& value = T())
        {
            if (n < size())
            {
                //缩小
                _finish = _start + n;
            }
            else//当n大于当前的size时
            {
                if (n > capacity()) reserve(n);

                while (_finish != _start + n)
                {
                    *_finish = value;
                    _finish++;
                }
            }
        }

modify

  1. push_back

    //需要先判断是否要扩容
        void push_back(const T& x)
        {
            if (_finish == _endOfStorage)
            {
                size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
            }
            *_finish = x;
            _finish++;
        }
    
  2. pop_back

    //最好断言一下,以至于来看看还有没有有效元素
           bool empty()const
           {
               return _start == _finish;
           }
           void pop_back()
           {
               assert(!empty());
               _finish--;
           }
    
  3. insert

//判断是否需要扩容,在此扩容之前记录一下pos和start的距离,然后扩容完之后移动元素,最后再插入元素。
        iterator insert(iterator pos, const T& x)
        {
            if (_finish == capacity())
            {
                size_t len = pos - _start;
                size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
                reserve(newcapacity);
                pos = _start + len;
            }

            size_t end = _finish;
            while (end >= pos)
            {
                *end = *(end - 1);
                --end;
            }
            //插入
            *pos = x;
            _finish++;
			return pos;
        }
  1. erase
//先判断是否为空,然后从前往后移动数据,最后_finish减减
        iterator erase(iterator pos)
        {
            assert(!empty());

            size_t end = pos + 1;
            while (end != _finish)
            {
                *(end - 1) = *(end);
                ++end;
            }
            _finish--;

            return pos;
        }

5.erase

//用库函数里面的swap
        void swap(vector<T>& v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endOfStorage, v._endOfStorage);
        }

accesee

  1. operator[]和const opeartor[]
        T& operator[](size_t pos)
        {
            assert(pos < size());
            return _start[pos];
        }
        const T& operator[](size_t pos)const
        {
            assert(pos < size());
            return _start[pos];
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值