【C++初阶8-vector实现】没想的那么简单!

前言

本期带来vector实现,和以前的顺序表差别不大。

博主水平有限,不足之处望请斧正!


预备知识

实现参考SGIstl30

我们看这种源码,要抓框架看:首先找类,看它的属性,再看方法

template <class T, class Alloc = alloc>
class vector {
public:
  typedef T value_type;
  typedef value_type* iterator;
  typedef const value_type* const_iterator;
  
  //...
  
protected:
  iterator start;
  iterator finish;
  iterator end_of_storage;
  
  //...
}

public:
  iterator begin() { return start; }
  const_iterator begin() const { return start; }
  iterator end() { return finish; }
  const_iterator end() const { return finish; }
	
	//...

}

可以看到,vector是使用三个迭代器 startfinishend_of_storage维护的,这是怎么个思路?

如图所示:

在这里插入图片描述

  • _start 指向起始位置
  • _finish 指向最后一个有效数据的下一个位置
  • _endofstorage 指向容量的下一个位置

有了这些储备,就能开始实现我们自己的vector了。

实现

分离

我们用一个 main.cpp 和一个 vector.h

#include <iostream>
using namespace std;

#include "vector.h"

int main()
{
		bacon::...; //调用测试函数
    return 0;
}

这里需要注意命名空间展开和包含头文件的顺序:为了编译速度,编译器找定义都是向上找。当 "vector.h" 展开,只会向上找——如果先包含 "vector.h" 后展开命名空间,"vector.h" 中使用 cout 之类向上就找不到。

跑起来
namespace bacon
{

template <class T>
class vector
{
public:
    typedef T* iterator;
    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; } 
    
    vector()
    :_start(nullptr)
    ,_finish(nullptr)
    ,_endofstorage(nullptr)
    {}
    
    size_t capacity() { return _endofstorage - _start; }
    
    size_t size() { return _finish - _start; }
    
    void reserve(size_t n)
    {
        if(n > capacity())
        {
            size_t oldsize = size();
            T* tmp = new T[n];
            if(_start)
            {
                memcpy(tmp, _start, sizeof(T) * size());
            }
            delete[] _start;

            _start = tmp;
            _finish = _start + size(); 
            _endofstorage = _start + size();
        }
    }
    
    void push_back(const T& val)
    {
        if(_finish == _endofstorage)
            reserve(capacity() == 0 ? 4 : capacity() * 2);
        
        *_finish = val;
        ++_finish;
    }
    
    T& operator[](size_t index)
    {
        assert(index < size());
        return _start[index];
    }
    
    
private:
    iterator _start;
    iterator _finish;
    iterator _endofstorage;
};

void test1()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    
    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    cout << endl;
}

}

//main.cpp
#include <iostream>
using namespace std;

#include "vector.h"

int main()
{
    bacon::test1();
    return 0;
}

测一下发现报错了

在这里插入图片描述

注意:reserve这里非常容易出bug

    void reserve(size_t n)
    {
        if(n > capacity())
        {
            T* tmp = new T[n];
            if(_start)
            {
                memcpy(tmp, _start, sizeof(T) * size());
            }
            delete[] _start;
            _start = tmp;
          	//size():return _finish - _start
          	//_finish = _start + _finish - _start; 
            _finish = _start + size(); 
            _endofstorage = _start + size();
        }
    }

size()本来应该用老的_start来和_finish作差,但是_start变了,导致size()返回的不是0,而是_finish - _start,原语句则变成_finish = _start + _finish - _start; 最终_finish还是nullptr

解决方案1:先更新_finish,仍然能用老的_start计算大小。

_finish = tmp + size();
_start = tmp;
_endofstorage = _start + size();

解决方案2:提前保存size,用临时保存的size迭代_finish_endofstorage

size_t oldsize = size();     
_start = tmp;
_finish = _start + oldsize;
_endofstorage = _start + oldsize;

所以reserve应该是这样:

		void reserve(size_t n)
    {
        if(n > capacity())
        {
            size_t oldsize = size();
            T* tmp = new T[n];
            if(_start)
            {
                memcpy(tmp, _start, sizeof(T) * size());
            }
            delete[] _start;

            //err:_start的改变影响size()
            //_finish = _start + size() = _start + _finish - _start = nullptr
            //1.调换顺序
            _finish = tmp + size();
            _start = tmp;
            _endofstorage = _start + size();
            
            //2.提前保存
            _start = tmp;
            _finish = _start + oldsize;
            _endofstorage = _start + n;
        }
    }

跑起来:

//vector.h
void test1()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    
    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    cout << endl;
}

//main.cpp
#include <iostream>
using namespace std;

#include "vector.h"

int main()
{
    bacon::test1();
    return 0;
}
1 2 3 4 1 2 3 4

补充成员函数
resizeempty
    void resize(size_t n, T val = T())
    {
        if(n > capacity()) reserve(n); //需要扩就扩了
        
        if(n > size())
        {
            while(_finish < _start + n)
            {
                *_finish = val;
                ++_finish;
            }
        }
        else
        {
            _finish = _start + n;
        }
    }
    
    bool empty() { return _start == _finish; }

resize

  1. 需要扩容则扩容

  2. n > size:填数据

  3. n <= size:删除数据

    (n == size)包含在哪种情况都一样

跑一下:

void test2()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    
    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    cout << endl;
    
    
    v.resize(100);
    cout << v.size() << endl;
    cout << v.capacity() << endl;
    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    cout << endl;
}

//main.c
#include <iostream>
using namespace std;

#include "vector.h"

int main()
{
    bacon::test2();
    return 0;
}
1 2 3 4 1 2 3 4 
100
8
1 2 3 4 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
pop_back
    void pop_back()
    {
        assert(!empty());
        --_finish;
    }
insert
		void insert(iterator pos, const T& val)
    {
        if(_finish == _endofstorage)
            reserve(capacity() == 0 ? 4 : capacity() * 2);
        
        iterator end = _finish - 1; //最后一个有效数据
        while(end >= pos)
        {
            *(end + 1) = *end;
            --end;
        }
        
        *pos = val;
        ++_finish;
    }

测一下,发现报错。

因为属性换成 _start 这些,挪动数据的时候不会有类型提升影响。那是什么问题?

其实是迭代器是小问题

#在insert内部,迭代器失效

为什么?

在这里插入图片描述

未扩容前:

在这里插入图片描述

pos仍正常,属于_start_finish 的范围内

在这里插入图片描述

扩容后:

在这里插入图片描述

画图分析一下:

在这里插入图片描述

扩容导致_start_finish 变化,所以pos已经不属于 _start_finish 的范围内了。此时,用 endpos 比较显然不是我们的意思了。

所以如果扩容了,需要更新一下 pos(按理也要检查一下pos)。

所以insert内部迭代器失效的原因是:扩容,未更新迭代器。

怎么解决?

更新迭代器

		void insert(iterator pos, const T& val)
    {
        assert(pos >= _start && pos < _finish);
        
        if(_finish == _endofstorage)
        {
            size_t len = pos - _start;
            reserve(capacity() == 0 ? 4 : capacity() * 2);
            pos = _start + len;
        }

        
        iterator end = _finish - 1; //最后一个有效数据
        while(end >= pos)
        {
            *(end + 1) = *end;
            --end;
        }
        
        *pos = val;
        ++_finish;
    }

在这里插入图片描述
:
在这里插入图片描述

更新成功。

void test4()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    cout << endl;
    
    v.insert(v.begin(), 9);
    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    cout << endl;
}
1 2 3 4 
9 1 2 3 4

insert内部迭代器失效

原因:扩容,迭代器未更新,导致迭代器野指针。

解决:更新迭代器。


#在insert外部,迭代器失效
void test4()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    cout << endl;
    
    vector<int>::iterator pos = find(v.begin(), v.end(), 2);
    v.insert(pos, 9);
    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    
    *(pos)++; //可以吗?
    
    cout << endl;
}

main insert以后,pos能否继续使用?

不能,有可能是失效的。insert 内的迭代器是传值传参得到的,不影响main内的 pos ,而我们仅在 insert 内 更新了迭代器,若 insert时发生扩容,mainpos 不会被更新。

那有什么方式可以解决?

传值不行,传引用?还是不行。引用形参只能接收左值(能修改的),当我们传了右值,如 v.begin(),调用返回涉及到临时变量,就会出错。

Error:非常量引用的初始值必须为左值

看看文档,发现还有个返回值

		iterator insert (iterator position, const value_type& val);

文档中这样描述返回值:

An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.

一个迭代器,指向被函数调用删除的最后一个元素之后的元素的新位置。如果操作擦除了序列中的最后一个元素,则这是容器结束。

比如,某迭代器原来指向 v[3],删除后指向新的 v[3],如果 v[3] 是最后一个元素,迭代器就是_finish

哦!当我们 insert 后还是需要用 pos ,通过返回值更新一下就好了!

		iterator insert(iterator pos, const T& val)
    {
        assert(pos >= _start && pos < _finish);
        
        if(_finish == _endofstorage)
        {
            size_t len = pos - _start;
            reserve(capacity() == 0 ? 4 : capacity() * 2);
            pos = _start + len;
        }

        
        iterator end = _finish - 1; //最后一个有效数据
        while(end >= pos)
        {
            *(end + 1) = *end;
            --end;
        }
        
        *pos = val;
        ++_finish;
        
        return pos;
    }

insert外部迭代器失效

原因:insert的迭代器参数是传值传参,内部更新不影响外部。main的迭代器仍然失效。

解决:外部按需通过返回值更新迭代器。

erase

经历前面的迭代器失效后,我们也想:这个会不会也导致迭代器失效呢?

好像不会哦?因为不缩容,空间不会变的。用库里的测一下,看库怎么说:

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

        std::vector<int>::iterator pos = find(v.begin(), v.end(), 3);
        v.erase(pos);
        for (size_t i = 0; i < v.size(); ++i)
        {
            cout << v[i] << ' ';
        }
        cout << endl;

        //读
        cout << *pos << endl;
        //写
        ++(*pos);  
     }

vs2022:

在这里插入图片描述

Xcode:

1 2 4 
4
#在erase外部,迭代器失效

为什么?

  1. 意义来说,迭代器如果不更新,是失效的(原来指向的数据都删了,现在指向谁说不准)
  2. 而且我们的代码得在所有平台能跑。

所以我们还是认为 erase 后,迭代器失效。

怎么解决?

同样的,通过返回值来选择性更新(需要再用就更新)。

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

erase外部迭代器失效

原因:意义改变

解决:按需通过返回值更新迭代器

find

可以直接用算法库的find

template<class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val)
{
  while (first!=last) {
    if (*first==val) return first;
    ++first;
  }
  return last;
}

算法库的find是函数模版,只需要我们的vector支持 != * ==++就行。

void test4()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    cout << endl;
    
    vector<int>::iterator pos = find(v.begin(), v.end(), 2);
  	if(pos != v.end())
    	v.insert(pos, 9);
    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v[i] << ' ';
    }
    cout << endl;
}
1 2 3 4 
1 9 2 3 4
swap
		void swap(vector<T>& v)
    {
        std::swap(this->_start, v._start);
        std::swap(this->_finish, v._finish);
        std::swap(this->_endofstorage, v._endofstorage);
    }
clear
    void clear() { _finish = _start; }
~vector
    ~vector()
    {
        delete[] _start;
        _start = _finish = _endofstorage = nullptr;
    }
vector(const vector<T>& v)

传统写法:开空间,拷贝数据(复用)

    vector(const vector<T>& v)
        :_start(nullptr)
        ,_finish(nullptr)
        ,_endofstorage(nullptr)
    {
        reserve(v.capacity());
        for(auto& e : v) 	//不加引用每次拿v内对象赋值给e,效率低
        {
            push_back(e);
        }
    }

现代写法:抓壮丁(迭代器区间构造)

vector(InputIterator first, InputIterator last)
    template <class InputIterator>
    vector(InputIterator first, InputIterator last)
        :_start(nullptr)
        ,_finish(nullptr)
        ,_endofstorage(nullptr)
    {
        while(first != last)
        {
            push_back(*first);
            ++first;
        }
    }
    vector(const vector<T>& v)
        :_start(nullptr)
        ,_finish(nullptr)
        ,_endofstorage(nullptr)
    {
        vector<T> man(v.begin(), v.end());
        swap(man);
    }
vector<T>& operator= (vector<T>& v)

现代写法:抓壮丁(传值传参调用拷贝构造产生的临时对象)

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

只要拷贝构造写好了,都能用这个现代写法~

但是,上面的写法有一个缺陷:v1 = v1,自己给自己赋值,白拷贝了。但可以容忍,因为这种场景非常少,而且程序能正常运行。

想实现全一点的话还可以实现一个这个。

explicit vector (size_type n, const value_type& val = value_type()

explicit:由于这是个单参构造,涉及赋值运算符的时候,若类型合适,可能将 n 转换为 vector

class t1
{
public:
	t1(int n) :_n(n) {}
private:
	int _n;
};

class t2
{
public:
	explicit t2(int n) :_n(n) {}
private:
	int _n;
};

int main()
{
	int num = 0;

	t1 t1 = num;
	
	t2 t2 = num;

	return 0;
}

如上,单参构造类型合适(int的形参和要初始化的属性合适),int n 转换成了t1 n

如此能防止单参构造的 n 转换为 vector

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

但是,这有个坑。

#n个val构造的匹配问题
void test9()
{
  	//vector<char> v(10, 'A'); //正常运行
    vector<int> v(10, 1);
    
    for(auto e : v)
        cout << e << ' ';
    cout << endl;
}

在这里插入图片描述

vector<int> v(10, 1);

vector(size_t n, const T& val = T())

template <class InputIterator>
    vector(InputIterator first, InputIterator last)

为什么vector<char> v(10, 'A');能匹配到vector(size_t n, const T& val = T())?

10这个字面量的类型是int'A'这个字面量的类型是char,模版参数T上绑定了char类型。虽然intsize_t有一点不匹配,但是可以类型转换,也没有其他更加匹配的函数。

而对于vector<int> v(10, 1);,两个字面量类型都是int,调用vector(size_t n, const T& val = T())需要将int转换为size_t,函数模版显然能产生更好的匹配,int被当做迭代器解引用,当然不行。

那如何解决呢?

想不到办法可以参考源码的实现

  vector() : start(0), finish(0), end_of_storage(0) {}
  vector(size_type n, const T& value) { fill_init ialize(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()); }

直接一样来一个。

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

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

原因:迭代器区间模版更匹配
解决:一样来一个,让它匹配

到这就差不多了……吗?

我们开空间的操作还有问题!拷数据简单地用memcpy就能解决吗?不能!当要拷贝的元素涉及深拷贝就完了!

#元素浅拷贝问题
void test11()
{
    vector<int> v(10, 1);
    vector<vector<int>> vv;
    
    vv.push_back(v);
    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;
    }
    cout << endl;
}

在这里插入图片描述

void reserve(size_t n)
    {
        if(n > capacity())
        {
            size_t oldsize = size();
            T* tmp = new T[n];
            if(_start)
            {
//                浅拷贝不够用,有些要深拷贝的
                memcpy(tmp, _start, sizeof(T) * size());
            }
            delete[] _start;
            
            _start = tmp;
            _finish = _start + oldsize;
            _endofstorage = _start + n;
        }
    }

对于reserve画图分析一下:

在这里插入图片描述

这是浅拷贝后未释放空间的情况,vv的属性直接拷贝给tmpvvtmp 指向同一块空间。这时再 delete[] _start; ,对每个自定义类型vector<int> v都调用析构,在这之前,每个vector<int> v 又会对自己的空间调用析构。
在这里插入图片描述

扩容后,vv指向新空间,但新空间的前4个元素的空间已经被析构,此时如果vv[0][0],解引用野指针,必然出错。

调试验证:

1.浅拷贝,新空间指向原空间

在这里插入图片描述

2.原空间释放,新空间受影响,[_start, _start+4) 变成野指针
在这里插入图片描述

3.解引用野指针(对野指针的访问,打印出随机值)

在这里插入图片描述

为什么说C++不适合用C语言的内存函数,这里若用realloc,其内部memcpy拷贝数据,完球。(要使用必须确定不会影响)

对于哪哪都是自定义类型的C++,我们尽量选择为其量身定制的new 和 delete,会自动调用构造和析构。

如何解决?自然是每个元素都深拷贝:

void reserve(size_t n)
    {
        if(n > capacity())
        {
            size_t oldsize = size();
            T* tmp = new T[n];
            if(_start)
            {
//                浅拷贝不够用,有些要深拷贝的
//                memcpy(tmp, _start, sizeof(T) * size());
                for(size_t i = 0; i < oldsize; ++i)
                {
                    tmp[i] = _start[i];
                }
            }
            delete[] _start;
            
            _start = tmp;
            _finish = _start + oldsize;
            _endofstorage = _start + n;
        }
    }

在这里插入图片描述

解决是解决了,效率是不是有点低?确实,现阶段没有好的解决办法,后期学了C++11就有了。

此处的问题不仅出现在刚刚的场景,只要是涉及 reserve 拷贝数据的地方,都会出现问题,如 拷贝构造 ,其中调用了 push_back,会调用到 reserve

vector的实现到这就差不多了,附上整体代码(如有错误不足之处,希望指出)

namespace bacon
{

template <class T>
class vector
{
public:
    typedef T* iterator;
    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; }
    
    vector()
    :_start(nullptr)
    ,_finish(nullptr)
    ,_endofstorage(nullptr)
    {}
    
    //explicit:对于单参的构造,类型合适的时候会触发隐式类型转换
    //这里是怕n隐式类型转换成vector,传size_t就不会转换成vector
    explicit vector(int n, const T& val = T())
    :_start(nullptr)
    ,_finish(nullptr)
    ,_endofstorage(nullptr)
    {
        reserve(n);
        for(int i = 0; i < n; ++i)
        {
            push_back(val);
        }
    }
    
    //按n的类型再给一个(long也能再给一个)方法,解决参数不匹配的问题
    explicit vector(size_t n, const T& val = T())
    :_start(nullptr)
    ,_finish(nullptr)
    ,_endofstorage(nullptr)
    {
        reserve(n);
        for(int i = 0; i < n; ++i)
        {
            push_back(val);
        }
    }
    
    template <class InputIterator>
    vector(InputIterator first, InputIterator last)
    :_start(nullptr)
    ,_finish(nullptr)
    ,_endofstorage(nullptr)
    //这里的实现体现了迭代器的意义,不同的迭代器,同样的控制,一套代码走所有容器
    {
        while(first != last)
        {
            push_back(*first);
            ++first;
        }
    }
    
    //现代写法
    vector(const vector<T>& v)
    :_start(nullptr)
    ,_finish(nullptr)
    ,_endofstorage(nullptr)
    {
        vector<T> man(v.begin(), v.end());
        swap(man);
    }
    
    //复用写法
    //    vector(const vector<T>& v)
    //        :_start(nullptr)
    //        ,_finish(nullptr)
    //        ,_endofstorage(nullptr)
    //    {
    //        reserve(v.capacity());
    //        for(auto& e : v) //不加引用每次拿v内对象赋值给e,效率低
    //        {
    //            push_back(e);
    //        }
    //    }
    

    ~vector()
    {
        delete[] _start;
        _start = _finish = _endofstorage = nullptr;
    }
    
    //v1 = v1
    vector<T>& operator= (vector<T> v)
    {
        swap(v);
        return *this;
    }
    
    bool empty() const { return _start == _finish; }
    
    size_t capacity() const { return _endofstorage - _start; }
    
    size_t size() const { return _finish - _start; }
    
    void reserve(size_t n)
    {
        if(n > capacity())
        {
            size_t oldsize = size();
            T* tmp = new T[n];
            if(_start)
            {
//                浅拷贝不够用,有些要深拷贝的
//                memcpy(tmp, _start, sizeof(T) * size());
                for(size_t i = 0; i < oldsize; ++i)
                {
                    tmp[i] = _start[i];
                }
            }
            delete[] _start;
            
            //err:_start的改变影响size()
            //_finish = _start + size() = _start + _finish - _start = nullptr
            //1.调换顺序
            //            _finish = tmp + size();
            //            _start = tmp;
            //            _endofstorage = _start + size();
            
            //2.提前保存
            _start = tmp;
            _finish = _start + oldsize;
            _endofstorage = _start + n;
        }
    }
    
    void resize(size_t n, T val = T())
    {
        //        1. 需要扩容则扩容
        //        2. n > size:填数据
        //        3. n <= size:删除数据
        //        (n == size)包含在哪种情况都一样
        if(n > capacity()) reserve(n); //需要扩就扩了
        
        if(n > size())
        {
            while(_finish < _start + n)
            {
                *_finish = val;
                ++_finish;
            }
        }
        else
        {
            _finish = _start + n;
        }
    }
    
    void push_back(const T& val)
    {
        if(_finish == _endofstorage)
            reserve(capacity() == 0 ? 4 : capacity() * 2);
        
        *_finish = val;
        ++_finish;
    }
    
    void pop_back()
    {
        assert(!empty());
        --_finish;
    }
    
    iterator insert(iterator pos, const T& val)
    {
        assert(pos >= _start && pos < _finish);
        
        if(_finish == _endofstorage)
        {
            size_t len = pos - _start;
            reserve(capacity() == 0 ? 4 : capacity() * 2);
            pos = _start + len;
        }
        
        
        iterator end = _finish - 1; //最后一个有效数据
        while(end >= pos)
        {
            *(end + 1) = *end;
            --end;
        }
        
        *pos = val;
        ++_finish;
        
        return pos;
    }
    
    iterator erase(iterator pos)
    {
        assert(!empty());
        assert(pos >= _start && pos < _finish);
        
        iterator begin = pos + 1;
        while(begin < _finish)
        {
            *(begin - 1) = *begin;
            ++begin;
        }
        --_finish;
        
        return pos;
    }
    
    void swap(vector<T>& v)
    {
        std::swap(this->_start, v._start);
        std::swap(this->_finish, v._finish);
        std::swap(this->_endofstorage, v._endofstorage);
    }
    
    void clear() { _finish = _start; }
    
    
    T& operator[](size_t index)
    {
        assert(index < size());
        return _start[index];
    }
    
    const T& operator[](size_t index) const
    {
        assert(index < size());
        return _start[index];
    }
    
    
private:
    iterator _start;
    iterator _finish;
    iterator _endofstorage;
};


}

重点回顾

insert内部的迭代器失效

  • 原因:扩容,迭代器未更新,野指针
  • 解决:需要扩容则更新迭代器

insert外部的迭代器失效

  • 原因:insert迭代器传值传参,内部更新不影响外部
  • 解决:按需用返回值更新迭代器

erase外部的迭代器失效

  • 原因:迭代器指向的数据已经删除,迭代器意义改变
  • 解决:按需用返回值更新迭代器

n个val构造类型不匹配

  • 原因:有些场景类型不够匹配,会走到迭代器区间构造(模版)
  • 解决:按n可能传的类型,多写几个这样的构造

元素浅拷贝问题

  • 原因:对自定义类型的元素浅拷贝,指向错误,导致新空间被影响
  • 解决:对每个元素的拷贝都调用它们自己的赋值重载或者拷贝构造等。

今天的分享就告一段落了。

这里是培根的blog,期待与你共同进步!

下期见~

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

周杰偷奶茶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值