vector模拟实现

成员变量

vector<>中可能是任意的数据类型,可能是譬如int,double这种内置类型,也有可能是类似于string类型的这种自定义类型,所以这里就需要使用到模版以及定义类型的指针

 template<class T>
typedef T* iterator;

成员变量一共有三 start,finish,endofstorage,切都是使用的iterator指针类型的 ,这样我们可以直接找到该地址,而不是用下标去访问,我们可以直接在声明的时候初始化,也可以在构造函数的时候使用初始化列表初始化

 iterator _start=nullptr;
        iterator _finish=nullptr;
        iterator _endofstorgae=nullptr;

构造,拷贝,析构函数

构造函数

构造函数由于本质是指针,因为我们已经在刚开始的时候在成员变量的时候初始化过了,所以可以不需要写初始化列表

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

 拷贝构造函数

假设我们要将v1的拷贝构造给v2,那么我们需要先给v2reserve出和v1相同的capacity,这个时候我们去取v1的capacity,然后我们再将v1的值pushback给v2

      vector(const vector<T>& v)
//                :_start(nullptr),
//                 _finish(nullptr),
//                 _endofstorgae(nullptr)
        {
            reserve(v.capacity());
            for(auto& e:v){
                push_back(e);
            }

        }

 

析构函数

析构函数我们直接delete start然后让我让start,finish和endofstorage指向空

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

操作符

operator=

这边我们可以直接写一个swap的函数去调用库中的swap函数

标准库中是将两个地址交换一下

 所以这边的swap函数就是将三个成员函数的地址交换一下,而原来this指针是指向空的,将空地址和tmp的地址使用swap函数去交换一下,值的注意的是,这边的swap里面的变量是用的赋值传参,而不是使用的引用传参,如果使用引用传参就会取到=右边的地址了,系统就会报错

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

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

 operator[]

取pos位置前需要先判断一下pos的位置是否合法

   T& operator[](size_t pos){
            assert(pos<size());
            return _start[pos];
        };
        const T& operator[](size_t pos)const{
            assert(pos<size());
            return _start[pos];
        };

增删查改 

capacity和size

endofstorage-start就是整个vector的capacity,如果只是定义未初始化,那么初始化的时候都给他们指向空了,所以等于0,size也是同样的道理

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

迭代器

迭代器我们设置一个只读的迭代器和可写迭代器begin指向start,end指向finish

   typedef const T* const_iterator;
        iterator begin(){
            return _start;
        }
        iterator end(){
            return _finish;
        }
        const_iterator begin()const{
            return _start;
        }
        const_iterator end()const{
            return _finish;
        }

reserve

在一开始的时候我们先用一个变量记录一下size的值,因为后面等start的地址发生改变再想取size的值就会出错的情况。如果n大于capacity再扩容,先定义一个tmp变量,如果start不为空则拷贝,这里需要值得注意,不能够使用memcpy去拷贝,这里涉及到一个深层次浅拷贝到问题,sizeof(T)为T成员变量的使用空间,如果这里是一个int类型的完全ok,如果是一个字符串类型的,这个_start会指向一块堆上的空间,这个空间有多大根据使用情况来定的,如果只用sizeof(T)那么则可能会发生报错的风险。

而使用for循环去拷贝,那么就不会造成报错,拷贝完后则del原来的start,再重新拷贝成员变量

  void reserve(size_t n){
            size_t sz=size();
            if(n>capacity()){
                T* tmp=new T[n];
                if(_start){
//                    memcpy(tmp,_start,sizeof(T)*size());//涉及到生层次浅拷贝问题
                for(size_t i=0;i<sz;i++){
                    tmp[i]=_start[i];
                }
                    delete[] _start;
                }
                _start=tmp;
                _finish=sz+_start;
                _endofstorgae=_start+n;
            }

        }

resize

resize就是控制size大小的,如果n<=size的话,那么直接让finish变成start+n即可。如果大于则扩容,扩容完则从finish位置去填入val,这里需要注意的是val不能填0,这边在定义的时候可能是其他的数据类型

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

string类型的resize 

int*类型的resize

 

push_back

先判断是否需要扩容,如果需要扩容则扩容,扩完容则赋值

 void push_back(const T& x){

            if(_finish==_endofstorgae){
                reserve(capacity()==0?4:2*capacity());              
            }
            *_finish=x;
            _finish++;
        }

insert

先判断pos是否是合法位置,是的话再插入

 void insert(iterator pos,const T& x){
                assert(pos>=_start);
                assert(pos<=_finish);

            if(_finish==_endofstorgae){
                size_t len=pos-_start;
                reserve(capacity()==0?4:2*capacity());
                pos=_start+len;
            }
            iterator end=_finish-1;
            while(pos<=end){
                *(end+1)=*end;
                end--;
            }
            *pos=x;
            _finish++;
        }
扩容引发迭代器失效问题1

扩容有可能会导致迭代器失效,如果上面这段代码的insert成员函数改成下面这样,扩容后pos还在原来的地址上,会导致迭代器失效的问题,此时会可能会发生内存错误

 void insert(iterator pos,const T& x){
                assert(pos>=_start);
                assert(pos<=_finish);

            if(_finish==_endofstorgae){
              //  size_t len=pos-_start;
                reserve(capacity()==0?4:2*capacity());
                //pos=_start+len;
            }
            iterator end=_finish-1;
            while(pos<=end){
                *(end+1)=*end;
                end--;
            }
            *pos=x;
            _finish++;
        }

扩容引发迭代器失效问题2

我们先定义一个it指针指向v.begin(),那么我们插入到扩容到时候,此时可能会引发异地扩容,那么it还是指向了之前的首地址,所以也就发生了失效问题

erase

erase代表了删除某个位置的值,我们先判断一下pos位置是否合法,再取it下一个位置的地址,将下一个位置的值往前移动则覆盖完成。

  iterator erase(iterator pos){
            assert(pos>=_start);
            assert(pos<_finish);
            iterator it=pos+1;
            while(it!=_finish){
                *(it-1)=*it;
                it++;
           ;
            }
            _finish--;
            return pos;
        }
删除引发的迭代器失效问题

下面这段代码有可能会引发迭代器失效,不同的编译器下检查的方式不一样,如果i%2成立删除了元素,那么会造成迭代器向后移动一个,再it++,就会跳过需要判断的数值

 使用其他数据类型来进行初始化

可以使用其他类型的数据结构来进行初始化,比如string使用int类型的迭代器区间,可能打进去的是字母

  template<class InputIterator>
        vector(InputIterator first,InputIterator last)
                :_start(nullptr),//clion编译器未做处理,在vs下会处理
                 _finish(nullptr),
                 _endofstorgae(nullptr)
        {
            while(first!=last){
                push_back((*first));
                ++first;
            }
        }

在初始化的时候赋值

这里的T& val=T()是代表了取的是T数据类型的空值,int的话可能是0,string可能是空

 vector(size_t n,const T& val=T()){
            reserve(n);
            for(size_t i=0;i<n;i++){
                push_back(val);
            }
        }
        vector(int n,const T& val=T()){
            reserve(n);
            for(int i=0;i<n;i++){
                push_back(val);
            }
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值