C++【STL】【vector类的模拟实现】【迭代器失效问题】

目录

一、vector容器的基本结构

二、vector容器的构造函数和析构函数

三、迭代器

四、返回容器中的相关参数

五、交换函数

六、拷贝构造

1.拷贝指定范围的数据

测试代码 

2.拷贝构造 

测试代码

3.使用=拷贝构造

七、扩容操作

1.reserve扩容

2.resize调整大小

测试代码

八、让我们的容器支持随机读写

九、尾插尾删 

1.尾插push_back

2.尾删 pop_back

3.将容器后面追加n个元素,元素为value 

测试代码 

十、随机位置插入和删除 

1.随机位置插入insert

2.随机位置擦除 

3.清除函数clear 

1)写法一:调用erase

2)写法二:直接将_finish=_start

测试代码

​编辑

测试代码(clear)

为什么要返回删除位置的下一个位置的迭代器? 

十一、迭代器的失效问题 

问题的解决 

测试代码

十二、vector的深拷贝和浅拷贝

传统写法:

现代写法:

测试代码:

潜在的匹配问题

解决方案

对多维vector的拷贝问题

解决方案

传统形式

现代形式

十三、主程序代码汇总 

十四、测试程序代码汇总

调用测试程序

测试程序

十五、vector原码


这里我们先将每一个小模块分别实现,然后最终的汇总代码和测试代码在后面

一、vector容器的基本结构

#pragma once
#include <stdio.h>
#include <assert.h>
namespace zhuyuan
{
    template<class T>
    class vector
    {
    public:
       
    private:
        //_start是容器的初始位置
        iterator _start;
        //finish是最后一个数据的下一个位置
        iterator _finish;
        //_end_of_storage是我们整个vector的容量大小
        iterator _end_of_storage;
    };
}

二、vector容器的构造函数和析构函数

        //空参构造器
        vector()
            :_start(nullptr)
            ,_finish(nullptr)
            ,_end_of_storage(nullptr)
        {

        }
        //析构函数
        ~vector()
        {
            //析构的时候只要将整一个空间的首元素的地址传过去就可以了。
            delete[] _start;
            _start=_finish=_end_of_storage= nullptr;
        }

三、迭代器

其实连续的空间的迭代器可以用指针来实现

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

四、返回容器中的相关参数

_end_of_storage表示的是容器中当前开辟的空间的最后位置的迭代器。

_start表示的是当前的容器的首元素的位置

_finish表示的当前容器中最后一个元素的下一个位置

capacity表示的是当前容器的容量大小

size表示的是当前容器中存储的元素个数

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

五、交换函数

对我们两个容器中的每一个成员变量都进行交换,交换可以直接调用我们的std中的交换函数。

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

六、拷贝构造

1.拷贝指定范围的数据

//将要拷贝的迭代器的范围传入
        vector(iterator first,iterator last)
                :_start(nullptr)
                ,_finish(nullptr)
                ,_end_of_storage(nullptr)
        {
            reserve(last-first+1);
            iterator it=begin();
            for(int i=0;i<last-first;i++)
            {
                *it=*(first+i);
                it++;
            }
            _finish=_start+(last-first);
        }

测试代码 

void myvector_test9()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        vector<int> v2(v1.begin(),v1.end());
        cout<<v2[1]<<endl;
    }

2.拷贝构造 

        vector(const vector<T>& v)
                : _start(nullptr)
                , _finish(nullptr)
                , _end_of_storage(nullptr)
        {
            reserve(v.capacity());
            iterator it = begin();
            const_iterator vit = v.begin();
            while (vit != v.end())
            {
                *it++ = *vit++;
            }
            _finish = it;
        }

测试代码

void myvector_test8()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        vector<int> v2(v1);
        vector<int>::iterator it=v2.begin();
        while(it!=v2.end())
        {
            cout<<*it<<" ";
            it++;
        }
        cout<<endl;
    }

3.使用=拷贝构造

这里我们可以采用和之前字符串中一样的老板式的写法

由于编译器在将v传过来的时候会拷贝构造一个v,将这个v与我们当前的容器中的内容交换一下,我们的当前容器就完成拷贝了

        vector<T>&operator =(vector<T> v)
        {
            swap(v);
            return *this;
        }
 void myvector_test10()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        vector<int> v2=v1;
        vector<int>::iterator it1=v1.begin();
        while(it1!=v1.end())
        {
            cout<<*it1<<" ";
            it1++;
        }
        cout<<endl;
        vector<int>::iterator it2=v2.begin();
        while(it2!=v2.end())
        {
            cout<<*it2<<" ";
            it2++;
        }
        cout<<endl;
    }

 

七、扩容操作

1.reserve扩容

reserve如果传入的数据比当前的空间大小小的话是不会处理的。

//开辟n个空间
        void reserve(size_t n)
        {
            if(n>capacity())
            {
                size_t  sz=size();
                T*tmp=new T[n];
                if(_start)
                {
                    memcpy(tmp,_start,sizeof(T)*size());
                    delete[] _start;
                }
                _start=tmp;
                _finish=_start+sz;
                //由于上面的过程中我们将原先的_start给销毁了,新的_start变成了tmp
                //所以其size可能会发生变化,
//                _finish=_start+size();
                _end_of_storage=_start+n;
            }
        }

2.resize调整大小

        //resize第一个参数是要调整到的大小,第二个参数是如果调整出来的大小大于了原来的数据用什么值填充
        void resize(size_t n,const T&value=T())
        {
            //1.如果n小于当前的size,则数据个数缩小到n
            if(n<=size())
            {
                _finish=_start+n;
                return;
            }
            //2.空间不够则增容
            if(n>capacity())
            {
                reserve(n);
            }
            //3.将size扩大到n
            iterator it=_finish;
            _finish=_start+n;
            while(it!=_finish)
            {
                *it=value;
                ++it;
            }

        }

测试代码

void myvector_test11()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        v1.push_back(4);
        vector<int>::iterator it1=v1.begin();
        while(it1!=v1.end())
        {
            cout<<*it1<<" ";
            it1++;
        }
        cout<<endl;
        vector<int>v2=v1;
        v1.resize(7,5);
        vector<int>::iterator it2=v1.begin();
        while(it2!=v1.end())
        {
            cout<<*it2<<" ";
            it2++;
        }
        cout<<endl;
    }

八、让我们的容器支持随机读写

我们分别需要提供const类型的和非const类型的。

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

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

九、尾插尾删 

1.尾插push_back

尾插要注意扩容

//使用泛型,输入的是T类型
        void push_back(const T&x)
        {
            if(_finish==_end_of_storage)
            {

                reserve(capacity()==0?4 :capacity()*2);

            }
            //finish是最后一个数据的下一个位置
            *_finish=x;
            ++_finish;
        }

2.尾删 pop_back

尾删我们需要先判断一下当前的容器还有没有元素

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

3.将容器后面追加n个元素,元素为value 

  vector<string> v;
//        如果下面的这个push_back不加const,就会报错,因为拷贝的这个字符串具有隐式类型转换
//        期间会生成一个中间的临时变量,而这个临时变量具有常性。如果不加const会发生权限的扩大。
//        v.push_back("xxxx")
        vector(size_t n, const T& value = T())
                : _start(nullptr)
                , _finish(nullptr)
                , _end_of_storage(nullptr)
        {
            reserve(n);
            while (n--)
            {
                push_back(value);
            }
        }

测试代码 

//使用迭代器遍历容器 
void Func(const vector<int>&v)
    {
        vector<int>::const_iterator it=v.begin();
        while(it!=v.end())
        {
            cout<<*it<<" ";
            ++it;
        }
        cout<<endl;
    }
    void myvector_test1()
    {

        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
        v.push_back(5);
//使用随机读取的方式遍历
        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
        vector<int>::iterator it=v.begin();
        while(it!=v.end())
        {
            cout<<*it<<" ";
            ++it;
        }
        cout<<endl;

        //使用范围for的形式遍历容器
        //有了迭代器就支持范围for,也就是调用我们的v.begin(),v.end()来执行相关的操作
        //const的话就走const的迭代器,
        for(auto e:v)
        {
            cout<<e<<" ";
        }
        v.pop_back();
        cout<<endl;

        Func(v);
    }

十、随机位置插入和删除 

1.随机位置插入insert

迭代器失效就是当我们尾插数据的时候,如果发生了扩容,原来的地址空间可能就被转换到了一块更大的空间,所以我们迭代器的指针就失效了。所以我们如果发生了扩容就要及时更新指针。

//        void insert(iterator &pos ,const T& x)
        void insert(iterator pos ,const T& x)
        {
            assert(pos>=_start);
            //等于finish就是尾插
            assert(pos<=_finish);
            if(_finish==_end_of_storage)
            {
                //如果发生了扩容就要重新调整我们的pos指针的位置,不然就会发生迭代器失效的问题
                size_t len=pos-_start;
                reserve(capacity()==0? 4:capacity()*2);
                //形参是实参的拷贝,并不会真正去改变我们外部的pos
                //仅仅只能保证我们下面的pos使用是正常的
                pos=_start+len;
            }
            //挪动数据
            iterator end=_finish -1;
            while(end>=pos)
            {
                *(end+1)=*end;
                --end;
            }
            *pos=x;
            ++_finish;
        }

2.随机位置擦除 

随机位置擦除的话可以使用缩容来优化我们过大的空间,但是这是一种时间换空间的做法,一般不用做。可以将下面代码中的缩容那部分注释掉。

        //stl规定erase返回删除位置的下一个位置迭代器
        iterator erase(iterator pos)
        {
            assert(pos>=_start);
            assert(pos<_finish);

            iterator begin=pos+1;
            //将当前位置不断挪动到前一个位置
            while(begin<_finish)
            {
                *(begin-1)=*begin;
                ++begin;
            }
            --_finish;

            if(size()<capacity()/2)
            {
                //缩容,以时间换空间。
                _end_of_storage=_start+capacity()/2;
            }
            return pos;
        }

3.清除函数clear 

1)写法一:调用erase

        void clear()
        {
            while(_finish!=_start)
            {
                erase(_start);
            }
        }

2)写法二:直接将_finish=_start

        void clear()
        {
            _finish = _start;
        }

测试代码

void myvector_test3()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
//    v.push_back(5);

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;

        v.erase(v.begin());
        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }

测试代码(clear)

 void myvector_test13()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        vector<int>::iterator it=v1.begin();
        while(it!=v1.end())
        {
            cout<<*it<<" ";
            it++;
        }
        cout<<endl;
        v1.clear();
        vector<int>::iterator it2=v1.begin();
        while(it2!=v1.end())
        {
            cout<<*it2<<" ";
            it2++;
        }
        cout<<endl;
    }

为什么要返回删除位置的下一个位置的迭代器? 

观察下面几个代码的变化和问题

 void myvector_test4()
    {
        //正常运行
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
        v.push_back(5);

        //要求删除所有的偶数
        auto it=v.begin();
        while(it!=v.end())
        {
            if(*it%2==0)
            {
                v.erase(it);
            }
            ++it;
        }

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }

相比于上面 这里我们少push_back了5

 //崩溃
    void myvector_test5()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);

        //要求删除所有的偶数
        auto it=v.begin();
        while(it!=v.end())
        {
            if(*it%2==0)
            {
                v.erase(it);
            }
            ++it;
        }
        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }

 ​​​​​​​

//4删不掉
    void myvector_test6()
    {
        //正常运行
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(4);
        v.push_back(3);
        v.push_back(4);
        v.push_back(5);
        v.push_back(5);
        
        //要求删除所有的偶数
        auto it=v.begin();
        while(it!=v.end())
        {
            if(*it%2==0)
            {
                v.erase(it);
            }
            ++it;
        }

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }

这里的4我们没删掉 

 正确的使用方式是我们在erase的时候就要同步更新我们的pos

 void myvector_test7()
    {
        //正常运行
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(4);
        v.push_back(3);
        v.push_back(4);
        v.push_back(5);

        //要求删除所有的偶数
        auto it=v.begin();
        while(it!=v.end())
        {
            if(*it%2==0)
            {
                //同步更新我们的it
                //如果删除了某个数据,it迭代器就不要继续往后走了
                //因为后面的数据会移动上来,it迭代器当前指向位置并没有检查过
                it=v.erase(it);
            }
            else
            {
                ++it;
            }

        }
        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }
    //结论:insert/erase pos位置,不要直接访问pos。
    // 一定要更新,直接访问,可能会出现各种出乎意料的结果
    //这就是pos所谓的迭代器失效。
    //认为pos失效,不要访问。
    //结果不同的底层实现可能不一样。

十一、迭代器的失效问题 

1.迭代器失效就是当我们尾插数据的时候,如果发生了扩容,原来的地址空间可能就被转换到了一块更大的空间,所以我们迭代器的指针就失效了,就变成了一个野指针(程序会崩溃)。

2.或者是迭代器在insert之后,因为数据的挪动,pos指向的位置已经不再是原来的值了

//迭代器失效问题
    void myvector_test2()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
//    v.push_back(5);

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;

        //这里由于我们之前扩容的写法(在上面的push_back中看),是初始开辟四个,然后超出的话空间直接乘以两倍,所以我们在第五个数据插入的时候就会发生扩容
        //在vector发生扩容的时候,我们的迭代器的指针就失效了,就会发生迭代器失效的问题
        auto p=find(v.begin(),v.end(),3);
        if(p!=v.end())
        {
            //在p位置插入数据以后,不要访问p,因为p可能失效
            v.insert(p,30);
            cout<<*p<<endl;
            //因为上面的insert30的时候p的指针已经失效了,所以会报错
            v.insert(p,40);
        }

        vector<int>::iterator it=v.begin();
        while(it!=v.end())
        {
            cout<<*it<<" ";
            ++it;
        }
        //如果上面的insert加了引用,下面这个代码就会报错。
        //传值返回的都是数据的临时拷贝,这个拷贝具有常性,不能被修改,会报错
        v.insert(v.begin(),1);
    }

问题的解决 

 我们同样可以仿照erase中的写法,将我们insert函数中当前的扩容之后的对应位置的迭代器返回,然后及时同步迭代器,从而解决这个问题。

        iterator insert(iterator pos ,const T& x)
        {
            assert(pos>=_start);
            //等于finish就是尾插
            assert(pos<=_finish);
            if(_finish==_end_of_storage)
            {
                //如果发生了扩容就要重新调整我们的pos指针的位置,不然就会发生迭代器失效的问题
                size_t len=pos-_start;
                reserve(capacity()==0? 4:capacity()*2);
                //形参是实参的拷贝,并不会真正去改变pos
                pos=_start+len;
            }
            //挪动数据
            iterator end=_finish -1;
            while(end>=pos)
            {
                *(end+1)=*end;
                --end;
            }
            *pos=x;
            ++_finish;
            return pos;
        }

测试代码

//迭代器失效问题
    void myvector_test12()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
//    v.push_back(5);

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;

        //在vector发生扩容的时候,我们的迭代器的指针就失效了,就会发生迭代器失效的问题
        auto p=find(v.begin(),v.end(),3);
        if(p!=v.end())
        {
            //在p位置插入数据以后,及时同步指针
            p=v.insert(p,30);
            for(size_t i=0;i<v.size();++i)
            {
                cout<<v[i]<<" ";
            }
            cout<<endl;
            p=v.insert(p,40);
        }

        vector<int>::iterator it=v.begin();
        while(it!=v.end())
        {
            cout<<*it<<" ";
            ++it;
        }
    }

但其实这个迭代器失效问题在不同的编译器和平台下都是不同的。因为STL仅仅是一个规范,并没有将具体的代码写死。比方说老师要叫你上网课,你可以在图书馆上网课,可以在寝室上网课,也可以在家里上网课。所以STL同理,在不同的平台下实现是不同的,所以同一个程序在不同的平台下会有不同的表现。

比方说VS下面就是用PJ版本的STL,g++下使用的是SGI版本的STL。

十二、vector的深拷贝和浅拷贝

传统写法:

写法一:

        //传统写法
        vector(const vector<T>&v)
        {
            _start=new T[v.size()];//
            memcpy(_start,v._start,sizeof(T)*v.size());
            _finish=_start+v.size();
            _end_of_storage=_start+v.size();
        }

写法二:

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

现代写法:

v1=v2默认的是浅拷贝,我们需要转换成深拷贝

写法一:

等于赋值

vector<T>&operator =(vector<T> v)
        {
            swap(v);
            return *this;
        }
        void swap(vector<T>& v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_end_of_storage, v._endOfStorage);
        }

拷贝构造 

//v2(v1)
        vector(const vector<T>& v)
                : _start(nullptr)
                , _finish(nullptr)
                , _end_of_storage(nullptr)
        {
            vector<T> tmp (v.begin(),v.end());
            swap(tmp);
        }

 

 写法二:

//现代写法
        //可以在模板里面再次嵌套模板
        template<class InputIterator>
        vector(InputIterator first,InputIterator last)
                : _start(nullptr)
                ,_finish(nullptr)
                , _end_of_storage(nullptr)
        {
            while(first!=last)
            {
                push_back(*first);
                ++first;
            }
        }
        //v2(v1)
        vector(const vector<T>& v)
                : _start(nullptr)
                , _finish(nullptr)
                , _end_of_storage(nullptr)
        {
            vector<T> tmp (v.begin(),v.end());
        }

 

测试代码:

 void myvector_test14()
     {
        //对于内置类型完整值拷贝,也就是浅拷贝
        //1.同一个空间会被析构两次
        //2.一个对象的修改会影响两个对象
        //面对自定义类型,就会调用对应的拷贝构造函数
        //深拷贝就是开辟一个与要拷贝的对象一样大的空间
        //然后逐个元素拷贝
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);

        vector<int> v1=v;
        cout<<"v"<<" ";
        for(auto e:v)
        {
            cout<<e<<" ";
        }
        cout<<endl;
         cout<<"v1"<<" ";
         for(auto e:v1)
         {
             cout<<e<<" ";
         }
         cout<<endl;
        v[2]*=2;
         cout<<"v"<<" ";
         for(auto e:v)
         {
             cout<<e<<" ";
         }
         cout<<endl;
         cout<<"v1"<<" ";
         for(auto e:v1)
         {
             cout<<e<<" ";
         }
         cout<<endl;
     }

 

 上面传入迭代器首尾位置的拷贝构造其实也可以拷贝string

void myvector_test15()
    {
        string s("hello world");
        vector<int> v(s.begin(),s.end());
        for(auto e:v)
        {
            cout<<(char)e<<" ";
        }
        cout<<endl;
    }

 

 测试调用=进行拷贝赋值

void myvector_test16()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);

        vector<int> v2;
        v2=v;
        for(auto e:v2)
        {
            cout<<e<<" ";
        }
        cout<<endl;

    }

 

潜在的匹配问题

void myvector_test17()
    {
        int i=0;
        //在c++中内置类型也有构造函数
        int j=int();
        cout<<j<<endl;
        int k=int (10);
        cout<<k<<endl;
        vector<int> v1(10);
        for(auto e:v1)
        {
            cout<<e<<" ";
        }
        cout<<endl;

        //非法的间接寻址
        //会报错
        i=1;
        //int int就出错了
        //因为编译器的匹配的时候会去寻找最匹配的那一个
        //所以这里匹配上了使用模板的那一个
        //但是我们的模板中的Inputiterator此时没有被解析成迭代器指针,反而别解析成了int
        //对int进行解引用,就会报错
//        vector<int> v2(10,i);
//        for(auto e:v2)
//        {
//            cout<<e<<" ";
//        }
//        cout<<endl;

        //不会报错
        //第一个是int,第二个是char
        vector<char> v3(10,'a');
        for(auto e:v3)
        {
            cout<<e<<" ";
        }
        cout<<endl;
    }

上面中间那个报错的就是因为匹配了这个 

​​​​​​​

解决方案

 官方的STL直接给了好几个不同的构造函数

所以我们可以写一个新的构造函数让它能够匹配上

我们将我们之前的这个函数修改一下

 

改成这个样子,让它能够匹配上

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

对多维vector的拷贝问题

下面的Solution中是我们之前写过的杨辉三角的代码,也就是需要拷贝一个二维的vector的代码,但是,但我们执行了下面的代码之后,发现程序会崩溃,这是为什么呢?

class Solution {
    public:
        vector<vector<int>> generate(int numRows) {
            vector<vector<int>> vv;
            vv.resize(numRows);
            for (size_t i = 0; i < vv.size(); ++i)
            {
                vv[i].resize(i + 1, 0);
                vv[i].front() = vv[i].back() = 1;
            }

            for (size_t i = 0; i < vv.size(); ++i)
            {
                for (size_t j = 0; j < vv[i].size(); ++j)
                {
                    if (vv[i][j] == 0)
                    {
                        vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
                    }
                }
            }

            for (size_t i = 0; i < vv.size(); ++i)
            {
                for (size_t j = 0; j < vv[i].size(); ++j)
                {
                    cout << vv[i][j] << " ";
                }
                cout << endl;
            }

            //vector<vector<int>> ret = vv;

            return vv;
        }
    };

    void test_vector11()
    {
        vector<vector<int>> ret = Solution().generate(5);
    }

 从下图中我们可以看出,虽然我们的vector<vector<int>>是一模一样地拷贝了一份,但是其中的每一个vector<int>中的数据所指向的都是同一片空间,所以在析构函数进行的时候,会发生两次析构,从而导致崩溃。

解决方案

传统形式

对于我们之前使用传统形式的拷贝的方式,我们是因为使用了memcpy才导致我们的两个二维容器中的一维容器指向了同一片空间,我们只需要景memcpy的拷贝方式改成下面的一个个逐个拷贝就可以了。

//v2(v1)
        vector(const vector<T>& v)
        {
        	_start = new T[v.size()]; // v.capacity()也可以
        	//memcpy(_start, v._start, sizeof(T)*v.size());
        	for (size_t i = 0; i < v.size(); ++i)
        	{
        		_start[i] = v._start[i];
        	}
        	_finish = _start + v.size();
        	_end_of_storage = _start + v.size();
        }

现代形式

我们注意到现代形式的写法中是用push_back拷贝的

 

push_back复用了insert 

 

 insert中调用了reserve进行我们上面的扩容操作, 

修改我们的reserve的代码

void reserve(size_t n)
        {
            if (n > capacity())
            {
                size_t sz = size();
                T* tmp = new T[n];
                if (_start)
                {
                    //memcpy(tmp, _start, sizeof(T)*sz);
                    for (size_t i = 0; i < sz; ++i)
                    {
                        //不要在用memcpy,而是一个元素一个元素地拷贝
                        tmp[i] = _start[i];
                    }
                    delete[] _start;
                }

                _start = tmp;
                _finish = _start + sz;
                _end_of_storage = _start + n;
            }
        }

成功实现拷贝 

 

 

十三、主程序代码汇总 


#ifndef VECTORTEST_MYVECTOR_H
#define VECTORTEST_MYVECTOR_H
#pragma once
#include <stdio.h>
#include <assert.h>
namespace zhuyuan
{
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;
        const typedef T* const_iterator;
        iterator begin()
        {
            return _start;
        }
        const iterator begin() const
        {
            return _start;
        }
        iterator end()
        {
            return _finish;
        }
        const iterator end() const
        {
            return _finish;
        }
        vector()
            :_start(nullptr)
            ,_finish(nullptr)
            ,_end_of_storage(nullptr)
        {

        }

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

        size_t capacity() const
        {
            return _end_of_storage-_start;
        }
        size_t  size() const
        {
            return _finish-_start;
        }
//        vector<string> v;
//        如果下面的这个push_back不加const,就会报错,因为拷贝的这个字符串具有隐式类型转换
//        期间会生成一个中间的临时变量,而这个临时变量具有常性。如果不加const会发生权限的扩大。
//        v.push_back("xxxx")
        vector(size_t n, const T& value = T())
                : _start(nullptr)
                , _finish(nullptr)
                , _end_of_storage(nullptr)
        {
            reserve(n);
            while (n--)
            {
                push_back(value);
            }
        }
        vector(iterator first,iterator last)
                :_start(nullptr)
                ,_finish(nullptr)
                ,_end_of_storage(nullptr)
        {
            reserve(last-first+1);
            iterator it=begin();
            for(int i=0;i<last-first;i++)
            {
                *it=*(first+i);
                it++;
            }
            _finish=_start+(last-first);
        }

        vector(const vector<T>& v)
                : _start(nullptr)
                , _finish(nullptr)
                , _end_of_storage(nullptr)
        {
            reserve(v.capacity());
            iterator it = begin();
            const_iterator vit = v.begin();
            while (vit != v.end())
            {
                *it++ = *vit++;
            }
            _finish = it;
        }
        vector<T>&operator =(vector<T> v)
        {
            swap(v);
            return *this;
        }
        void swap(vector<T>& v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_end_of_storage, v._endOfStorage);
        }
        //开辟n个空间
        void reserve(size_t n)
        {
            if(n>capacity())
            {
                size_t  sz=size();
                T*tmp=new T[n];
                if(_start)
                {
                    memcpy(tmp,_start,sizeof(T)*size());
                    delete[] _start;
                }
                _start=tmp;
                _finish=_start+sz;
                //由于上面的过程中我们将原先的_start给销毁了,新的_start变成了tmp
                //所以其size可能会发生变化,
//                _finish=_start+size();
                _end_of_storage=_start+n;
            }
        }
        //resize第一个参数是要调整到的大小,第二个参数是如果调整出来的大小大于了原来的数据用什么值填充
        void resize(size_t n,const T&value=T())
        {
            //1.如果n小于当前的size,则数据个数缩小到n
            if(n<=size())
            {
                _finish=_start+n;
                return;
            }
            //2.空间不够则增容
            if(n>capacity())
            {
                reserve(n);
            }
            //3.将size扩大到n
            iterator it=_finish;
            _finish=_start+n;
            while(it!=_finish)
            {
                *it=value;
                ++it;
            }

        }

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

        T&operator [](size_t pos)
        {
            assert(pos<size());
            return _start[pos];
        }
        //使用泛型,输入的是T类型
        void push_back(const T&x)
        {
            if(_finish==_end_of_storage)
            {

                reserve(capacity()==0?4 :capacity()*2);

            }
            //finish是最后一个数据的下一个位置
            *_finish=x;
            ++_finish;
        }

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

//        void insert(iterator &pos ,const T& x)
        iterator insert(iterator pos ,const T& x)
        {
            assert(pos>=_start);
            //等于finish就是尾插
            assert(pos<=_finish);
            if(_finish==_end_of_storage)
            {
                //如果发生了扩容就要重新调整我们的pos指针的位置,不然就会发生迭代器失效的问题
                size_t len=pos-_start;
                reserve(capacity()==0? 4:capacity()*2);
                //形参是实参的拷贝,并不会真正去改变pos
                pos=_start+len;
            }
            //挪动数据
            iterator end=_finish -1;
            while(end>=pos)
            {
                *(end+1)=*end;
                --end;
            }
            *pos=x;
            ++_finish;
            return pos;
        }
        //stl规定erase返回删除位置的下一个位置迭代器
        iterator erase(iterator pos)
        {
            assert(pos>=_start);
            assert(pos<_finish);

            iterator begin=pos+1;
            //将当前位置不断挪动到前一个位置
            while(begin<_finish)
            {
                *(begin-1)=*begin;
                ++begin;
            }
            --_finish;

            if(size()<capacity()/2)
            {
                //缩容,以时间换空间。
                _end_of_storage=_start+capacity()/2;
            }
            return pos;
        }
    private:
        iterator _start;
        //finish是最后一个数据的下一个位置
        iterator _finish;
        //_end_of_storage是我们整个vector的容量大小
        iterator _end_of_storage;
    };


}
#endif //VECTORTEST_MYVECTOR_H

十四、测试程序代码汇总

调用测试程序

using namespace std;
#include "myvector.h"

int main()
{
    try
    {
        zhuyuan::myvector_test1();
    }
    catch(std::exception&e)
    {
        std::cout<<e.what()<<std::endl;
    }
}

测试程序

    void Func(const vector<int>&v)
    {
        vector<int>::const_iterator it=v.begin();
        while(it!=v.end())
        {
            cout<<*it<<" ";
            ++it;
        }
        cout<<endl;
    }
    void myvector_test1()
    {

        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
        v.push_back(5);

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
        vector<int>::iterator it=v.begin();
        while(it!=v.end())
        {
            cout<<*it<<" ";
            ++it;
        }
        cout<<endl;

        //有了迭代器就支持范围for,也就是调用我们的v.begin(),v.end()来执行相关的操作
        //const的话就走const的迭代器,
        for(auto e:v)
        {
            cout<<e<<" ";
        }
        v.pop_back();
        cout<<endl;

        Func(v);
    }
//迭代器失效问题
    void myvector_test2()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
//    v.push_back(5);

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;

        //在vector发生扩容的时候,我们的迭代器的指针就失效了,就会发生迭代器失效的问题
        auto p=find(v.begin(),v.end(),3);
        if(p!=v.end())
        {
            //在p位置插入数据以后,不要访问p,因为p可能失效
            v.insert(p,30);
            cout<<*p<<endl;
            v.insert(p,40);
        }

        vector<int>::iterator it=v.begin();
        while(it!=v.end())
        {
            cout<<*it<<" ";
            ++it;
        }
        //如果上面的insert加了引用,下面这个代码就会报错。
        //传值返回的都是数据的临时拷贝,这个拷贝具有常性,不能被修改,会报错
        v.insert(v.begin(),1);
    }
    void myvector_test3()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
//    v.push_back(5);

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;

        v.erase(v.begin());
        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }
    void myvector_test4()
    {
        //正常运行
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
        v.push_back(5);

        //要求删除所有的偶数
        auto it=v.begin();
        while(it!=v.end())
        {
            if(*it%2==0)
            {
                v.erase(it);
            }
            ++it;
        }

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }

    //崩溃
    void myvector_test5()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);

        //要求删除所有的偶数
        auto it=v.begin();
        while(it!=v.end())
        {
            cout<<"it"<<*it<<endl;
//            cout<<*it<<endl;
            if(*it%2==0)
            {
                cout<<"end()"<<v.end()-v.begin()<<endl;
                v.erase(it);
            }
            ++it;
        }
        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }
    //4删不掉
    void myvector_test6()
    {
        //正常运行
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(4);
        v.push_back(3);
        v.push_back(4);
        v.push_back(5);
        v.push_back(5);

        //要求删除所有的偶数
        auto it=v.begin();
        while(it!=v.end())
        {
            if(*it%2==0)
            {
                v.erase(it);
            }
            ++it;
        }

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }
    void myvector_test7()
    {
        //正常运行
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(4);
        v.push_back(3);
        v.push_back(4);
        v.push_back(5);

        //要求删除所有的偶数
        auto it=v.begin();
        while(it!=v.end())
        {
            if(*it%2==0)
            {
                it=v.erase(it);
            }
            else
            {
                ++it;
            }

        }
        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }
    //结论:insert/erase pos位置,不要直接访问pos。
    // 一定要更新,直接访问,可能会出现各种出乎意料的结果
    //这就是pos所谓的迭代器失效。
    //认为pos失效,不要访问。
    //结果不同的底层实现可能不一样。
    void myvector_test8()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        vector<int> v2(v1);
        vector<int>::iterator it=v2.begin();
        while(it!=v2.end())
        {
            cout<<*it<<" ";
            it++;
        }
        cout<<endl;
    }

    void myvector_test9()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        vector<int> v2(v1.begin(),v1.end());
        cout<<v2[1]<<endl;
    }
    void myvector_test10()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        vector<int> v2=v1;
        vector<int>::iterator it1=v1.begin();
        while(it1!=v1.end())
        {
            cout<<*it1<<" ";
            it1++;
        }
        cout<<endl;
        vector<int>::iterator it2=v2.begin();
        while(it2!=v2.end())
        {
            cout<<*it2<<" ";
            it2++;
        }
        cout<<endl;
    }
    void myvector_test11()
    {
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        v1.push_back(4);
        vector<int>::iterator it1=v1.begin();
        while(it1!=v1.end())
        {
            cout<<*it1<<" ";
            it1++;
        }
        cout<<endl;
        vector<int>v2=v1;
        v1.resize(7,5);
        vector<int>::iterator it2=v1.begin();
        while(it2!=v1.end())
        {
            cout<<*it2<<" ";
            it2++;
        }
        cout<<endl;
    }


    //迭代器失效问题
    void myvector_test12()
    {
        vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(4);
//    v.push_back(5);

        for(size_t i=0;i<v.size();++i)
        {
            cout<<v[i]<<" ";
        }
        cout<<endl;

        //在vector发生扩容的时候,我们的迭代器的指针就失效了,就会发生迭代器失效的问题
        auto p=find(v.begin(),v.end(),3);
        if(p!=v.end())
        {
            //在p位置插入数据以后,及时同步指针
            p=v.insert(p,30);
            for(size_t i=0;i<v.size();++i)
            {
                cout<<v[i]<<" ";
            }
            cout<<endl;
            p=v.insert(p,40);
        }

        vector<int>::iterator it=v.begin();
        while(it!=v.end())
        {
            cout<<*it<<" ";
            ++it;
        }
    }

十五、vector原码

可以对照原码查看我们上面的模拟实现代码

/*
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  Hewlett-Packard Company makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 *
 * Copyright (c) 1996
 * Silicon Graphics Computer Systems, Inc.
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  Silicon Graphics makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 */

/* NOTE: This is an internal header file, included by other STL headers.
 *   You should not attempt to use it directly.
 */

#ifndef __SGI_STL_INTERNAL_VECTOR_H
#define __SGI_STL_INTERNAL_VECTOR_H

__STL_BEGIN_NAMESPACE 

#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma set woff 1174
#endif

template <class T, class Alloc = alloc>
class vector {
public:
  typedef T value_type;
  typedef value_type* pointer;
  typedef const value_type* const_pointer;
  typedef value_type* iterator;
  typedef const value_type* const_iterator;
  typedef value_type& reference;
  typedef const value_type& const_reference;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;

#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
  typedef reverse_iterator<const_iterator> const_reverse_iterator;
  typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
  typedef reverse_iterator<const_iterator, value_type, const_reference, 
                           difference_type>  const_reverse_iterator;
  typedef reverse_iterator<iterator, value_type, reference, difference_type>
          reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
protected:
  typedef simple_alloc<value_type, Alloc> data_allocator;
  iterator start;
  iterator finish;
  iterator end_of_storage;
  void insert_aux(iterator position, const T& x);
  void deallocate() {
    if (start) data_allocator::deallocate(start, end_of_storage - start);
  }

  void fill_initialize(size_type n, const T& value) {
    start = allocate_and_fill(n, value);
    finish = start + n;
    end_of_storage = finish;
  }
public:
  iterator begin() { return start; }
  const_iterator begin() const { return start; }
  iterator end() { return finish; }
  const_iterator end() const { return finish; }
  reverse_iterator rbegin() { return reverse_iterator(end()); }
  const_reverse_iterator rbegin() const { 
    return const_reverse_iterator(end()); 
  }
  reverse_iterator rend() { return reverse_iterator(begin()); }
  const_reverse_iterator rend() const { 
    return const_reverse_iterator(begin()); 
  }
  size_type size() const { return size_type(end() - begin()); }
  size_type max_size() const { return size_type(-1) / sizeof(T); }
  size_type capacity() const { return size_type(end_of_storage - begin()); }
  bool empty() const { return begin() == end(); }
  reference operator[](size_type n) { return *(begin() + n); }
  const_reference operator[](size_type n) const { return *(begin() + n); }

  vector() : start(0), finish(0), end_of_storage(0) {}
  vector(size_type n, const T& value) { fill_initialize(n, value); }
  vector(int n, const T& value) { fill_initialize(n, value); }
  vector(long n, const T& value) { fill_initialize(n, value); }
  explicit vector(size_type n) { fill_initialize(n, T()); }

  vector(const vector<T, Alloc>& x) {
    start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
    finish = start + (x.end() - x.begin());
    end_of_storage = finish;
  }
#ifdef __STL_MEMBER_TEMPLATES
  template <class InputIterator>
  vector(InputIterator first, InputIterator last) :
    start(0), finish(0), end_of_storage(0)
  {
    range_initialize(first, last, iterator_category(first));
  }
#else /* __STL_MEMBER_TEMPLATES */
  vector(const_iterator first, const_iterator last) {
    size_type n = 0;
    distance(first, last, n);
    start = allocate_and_copy(n, first, last);
    finish = start + n;
    end_of_storage = finish;
  }
#endif /* __STL_MEMBER_TEMPLATES */
  ~vector() { 
    destroy(start, finish);
    deallocate();
  }
  vector<T, Alloc>& operator=(const vector<T, Alloc>& x);
  void reserve(size_type n) {
    if (capacity() < n) {
      const size_type old_size = size();
      iterator tmp = allocate_and_copy(n, start, finish);
      destroy(start, finish);
      deallocate();
      start = tmp;
      finish = tmp + old_size;
      end_of_storage = start + n;
    }
  }
  reference front() { return *begin(); }
  const_reference front() const { return *begin(); }
  reference back() { return *(end() - 1); }
  const_reference back() const { return *(end() - 1); }
  void push_back(const T& x) {
    if (finish != end_of_storage) {
      construct(finish, x);
      ++finish;
    }
    else
      insert_aux(end(), x);
  }
  void swap(vector<T, Alloc>& x) {
    __STD::swap(start, x.start);
    __STD::swap(finish, x.finish);
    __STD::swap(end_of_storage, x.end_of_storage);
  }
  iterator insert(iterator position, const T& x) {
    size_type n = position - begin();
    if (finish != end_of_storage && position == end()) {
      construct(finish, x);
      ++finish;
    }
    else
      insert_aux(position, x);
    return begin() + n;
  }
  iterator insert(iterator position) { return insert(position, T()); }
#ifdef __STL_MEMBER_TEMPLATES
  template <class InputIterator>
  void insert(iterator position, InputIterator first, InputIterator last) {
    range_insert(position, first, last, iterator_category(first));
  }
#else /* __STL_MEMBER_TEMPLATES */
  void insert(iterator position,
              const_iterator first, const_iterator last);
#endif /* __STL_MEMBER_TEMPLATES */

  void insert (iterator pos, size_type n, const T& x);
  void insert (iterator pos, int n, const T& x) {
    insert(pos, (size_type) n, x);
  }
  void insert (iterator pos, long n, const T& x) {
    insert(pos, (size_type) n, x);
  }

  void pop_back() {
    --finish;
    destroy(finish);
  }
  iterator erase(iterator position) {
    if (position + 1 != end())
      copy(position + 1, finish, position);
    --finish;
    destroy(finish);
    return position;
  }
  iterator erase(iterator first, iterator last) {
    iterator i = copy(last, finish, first);
    destroy(i, finish);
    finish = finish - (last - first);
    return first;
  }
  void resize(size_type new_size, const T& x) {
    if (new_size < size()) 
      erase(begin() + new_size, end());
    else
      insert(end(), new_size - size(), x);
  }
  void resize(size_type new_size) { resize(new_size, T()); }
  void clear() { erase(begin(), end()); }

protected:
  iterator allocate_and_fill(size_type n, const T& x) {
    iterator result = data_allocator::allocate(n);
    __STL_TRY {
      uninitialized_fill_n(result, n, x);
      return result;
    }
    __STL_UNWIND(data_allocator::deallocate(result, n));
  }

#ifdef __STL_MEMBER_TEMPLATES
  template <class ForwardIterator>
  iterator allocate_and_copy(size_type n,
                             ForwardIterator first, ForwardIterator last) {
    iterator result = data_allocator::allocate(n);
    __STL_TRY {
      uninitialized_copy(first, last, result);
      return result;
    }
    __STL_UNWIND(data_allocator::deallocate(result, n));
  }
#else /* __STL_MEMBER_TEMPLATES */
  iterator allocate_and_copy(size_type n,
                             const_iterator first, const_iterator last) {
    iterator result = data_allocator::allocate(n);
    __STL_TRY {
      uninitialized_copy(first, last, result);
      return result;
    }
    __STL_UNWIND(data_allocator::deallocate(result, n));
  }
#endif /* __STL_MEMBER_TEMPLATES */


#ifdef __STL_MEMBER_TEMPLATES
  template <class InputIterator>
  void range_initialize(InputIterator first, InputIterator last,
                        input_iterator_tag) {
    for ( ; first != last; ++first)
      push_back(*first);
  }

  // This function is only called by the constructor.  We have to worry
  //  about resource leaks, but not about maintaining invariants.
  template <class ForwardIterator>
  void range_initialize(ForwardIterator first, ForwardIterator last,
                        forward_iterator_tag) {
    size_type n = 0;
    distance(first, last, n);
    start = allocate_and_copy(n, first, last);
    finish = start + n;
    end_of_storage = finish;
  }

  template <class InputIterator>
  void range_insert(iterator pos,
                    InputIterator first, InputIterator last,
                    input_iterator_tag);

  template <class ForwardIterator>
  void range_insert(iterator pos,
                    ForwardIterator first, ForwardIterator last,
                    forward_iterator_tag);

#endif /* __STL_MEMBER_TEMPLATES */
};

template <class T, class Alloc>
inline bool operator==(const vector<T, Alloc>& x, const vector<T, Alloc>& y) {
  return x.size() == y.size() && equal(x.begin(), x.end(), y.begin());
}

template <class T, class Alloc>
inline bool operator<(const vector<T, Alloc>& x, const vector<T, Alloc>& y) {
  return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
}

#ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDER

template <class T, class Alloc>
inline void swap(vector<T, Alloc>& x, vector<T, Alloc>& y) {
  x.swap(y);
}

#endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER */

template <class T, class Alloc>
vector<T, Alloc>& vector<T, Alloc>::operator=(const vector<T, Alloc>& x) {
  if (&x != this) {
    if (x.size() > capacity()) {
      iterator tmp = allocate_and_copy(x.end() - x.begin(),
                                       x.begin(), x.end());
      destroy(start, finish);
      deallocate();
      start = tmp;
      end_of_storage = start + (x.end() - x.begin());
    }
    else if (size() >= x.size()) {
      iterator i = copy(x.begin(), x.end(), begin());
      destroy(i, finish);
    }
    else {
      copy(x.begin(), x.begin() + size(), start);
      uninitialized_copy(x.begin() + size(), x.end(), finish);
    }
    finish = start + x.size();
  }
  return *this;
}

template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
  if (finish != end_of_storage) {
    construct(finish, *(finish - 1));
    ++finish;
    T x_copy = x;
    copy_backward(position, finish - 2, finish - 1);
    *position = x_copy;
  }
  else {
    const size_type old_size = size();
    const size_type len = old_size != 0 ? 2 * old_size : 1;
    iterator new_start = data_allocator::allocate(len);
    iterator new_finish = new_start;
    __STL_TRY {
      new_finish = uninitialized_copy(start, position, new_start);
      construct(new_finish, x);
      ++new_finish;
      new_finish = uninitialized_copy(position, finish, new_finish);
    }

#       ifdef  __STL_USE_EXCEPTIONS 
    catch(...) {
      destroy(new_start, new_finish); 
      data_allocator::deallocate(new_start, len);
      throw;
    }
#       endif /* __STL_USE_EXCEPTIONS */
    destroy(begin(), end());
    deallocate();
    start = new_start;
    finish = new_finish;
    end_of_storage = new_start + len;
  }
}

template <class T, class Alloc>
void vector<T, Alloc>::insert(iterator position, size_type n, const T& x) {
  if (n != 0) {
    if (size_type(end_of_storage - finish) >= n) {
      T x_copy = x;
      const size_type elems_after = finish - position;
      iterator old_finish = finish;
      if (elems_after > n) {
        uninitialized_copy(finish - n, finish, finish);
        finish += n;
        copy_backward(position, old_finish - n, old_finish);
        fill(position, position + n, x_copy);
      }
      else {
        uninitialized_fill_n(finish, n - elems_after, x_copy);
        finish += n - elems_after;
        uninitialized_copy(position, old_finish, finish);
        finish += elems_after;
        fill(position, old_finish, x_copy);
      }
    }
    else {
      const size_type old_size = size();        
      const size_type len = old_size + max(old_size, n);
      iterator new_start = data_allocator::allocate(len);
      iterator new_finish = new_start;
      __STL_TRY {
        new_finish = uninitialized_copy(start, position, new_start);
        new_finish = uninitialized_fill_n(new_finish, n, x);
        new_finish = uninitialized_copy(position, finish, new_finish);
      }
#         ifdef  __STL_USE_EXCEPTIONS 
      catch(...) {
        destroy(new_start, new_finish);
        data_allocator::deallocate(new_start, len);
        throw;
      }
#         endif /* __STL_USE_EXCEPTIONS */
      destroy(start, finish);
      deallocate();
      start = new_start;
      finish = new_finish;
      end_of_storage = new_start + len;
    }
  }
}

#ifdef __STL_MEMBER_TEMPLATES

template <class T, class Alloc> template <class InputIterator>
void vector<T, Alloc>::range_insert(iterator pos,
                                    InputIterator first, InputIterator last,
                                    input_iterator_tag) {
  for ( ; first != last; ++first) {
    pos = insert(pos, *first);
    ++pos;
  }
}

template <class T, class Alloc> template <class ForwardIterator>
void vector<T, Alloc>::range_insert(iterator position,
                                    ForwardIterator first,
                                    ForwardIterator last,
                                    forward_iterator_tag) {
  if (first != last) {
    size_type n = 0;
    distance(first, last, n);
    if (size_type(end_of_storage - finish) >= n) {
      const size_type elems_after = finish - position;
      iterator old_finish = finish;
      if (elems_after > n) {
        uninitialized_copy(finish - n, finish, finish);
        finish += n;
        copy_backward(position, old_finish - n, old_finish);
        copy(first, last, position);
      }
      else {
        ForwardIterator mid = first;
        advance(mid, elems_after);
        uninitialized_copy(mid, last, finish);
        finish += n - elems_after;
        uninitialized_copy(position, old_finish, finish);
        finish += elems_after;
        copy(first, mid, position);
      }
    }
    else {
      const size_type old_size = size();
      const size_type len = old_size + max(old_size, n);
      iterator new_start = data_allocator::allocate(len);
      iterator new_finish = new_start;
      __STL_TRY {
        new_finish = uninitialized_copy(start, position, new_start);
        new_finish = uninitialized_copy(first, last, new_finish);
        new_finish = uninitialized_copy(position, finish, new_finish);
      }
#         ifdef __STL_USE_EXCEPTIONS
      catch(...) {
        destroy(new_start, new_finish);
        data_allocator::deallocate(new_start, len);
        throw;
      }
#         endif /* __STL_USE_EXCEPTIONS */
      destroy(start, finish);
      deallocate();
      start = new_start;
      finish = new_finish;
      end_of_storage = new_start + len;
    }
  }
}

#else /* __STL_MEMBER_TEMPLATES */

template <class T, class Alloc>
void vector<T, Alloc>::insert(iterator position, 
                              const_iterator first, 
                              const_iterator last) {
  if (first != last) {
    size_type n = 0;
    distance(first, last, n);
    if (size_type(end_of_storage - finish) >= n) {
      const size_type elems_after = finish - position;
      iterator old_finish = finish;
      if (elems_after > n) {
        uninitialized_copy(finish - n, finish, finish);
        finish += n;
        copy_backward(position, old_finish - n, old_finish);
        copy(first, last, position);
      }
      else {
        uninitialized_copy(first + elems_after, last, finish);
        finish += n - elems_after;
        uninitialized_copy(position, old_finish, finish);
        finish += elems_after;
        copy(first, first + elems_after, position);
      }
    }
    else {
      const size_type old_size = size();
      const size_type len = old_size + max(old_size, n);
      iterator new_start = data_allocator::allocate(len);
      iterator new_finish = new_start;
      __STL_TRY {
        new_finish = uninitialized_copy(start, position, new_start);
        new_finish = uninitialized_copy(first, last, new_finish);
        new_finish = uninitialized_copy(position, finish, new_finish);
      }
#         ifdef __STL_USE_EXCEPTIONS
      catch(...) {
        destroy(new_start, new_finish);
        data_allocator::deallocate(new_start, len);
        throw;
      }
#         endif /* __STL_USE_EXCEPTIONS */
      destroy(start, finish);
      deallocate();
      start = new_start;
      finish = new_finish;
      end_of_storage = new_start + len;
    }
  }
}

#endif /* __STL_MEMBER_TEMPLATES */

#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma reset woff 1174
#endif

__STL_END_NAMESPACE 

#endif /* __SGI_STL_INTERNAL_VECTOR_H */

// Local Variables:
// mode:C++
// End:

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桜キャンドル淵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值