成员变量 和 成员函数
由于vector的特性,我们只需要三个指针就能完成对整个vector的控制
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _endofstorage = nullptr;
};
其中_start指向的是vector的第一个元素
_finish指向的是vector的最后一个元素的后一个位置
_endofstorage 指向整个vector空间的最后一个位置
有了这三个指针我们就能控制整个的vector了
成员函数:
begin和end
iterator begin()const
{
return _start;
}
iterator end()const
{
return _finish;
}
const_iterator cbegin() const
{
return _start;
}
const_iterator cend() const
{
return _finish;
}
我们的_start指向的恰好就是向量的第一个元素,所以begin( )直接就返回_start就可以了
end( )应该要返回的不是最后一个元素,应该是最后一个元素的后面一个位置,所以直接返回_finish就可以!
size和capacity
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endofstorage - _start;
}
因为我们的_finish指向的不是最后一个元素,而是再后边一个元素,所以我们的size( )刚好等于_finish 与 _start 直接的距离再除以val_type的大小 ,所以直接返回_finish - _start
由于_endofstorage记录的是vector空间的最后位置,所以直接返回与_start 的差值 就是我们需要的capacity( )
operator[ ]
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos) const
{
assert(pos < size());
return _start[pos];
}
由于 ptr[ pos ]与 *( ptr + pos)等价 所以我们的operator [ ] 也可以写成第二种形式
*( _start + pos) 要注意的是,我们传的参数 pos 应该满足不能让vector发生越界 ,
所以这里直接暴力断言 pos<size( )
修改容量的函数
void reserve(size_t n)
{
if (n > capacity())
{
size_t old = size();
T* tmp = new T[n];
if (_start)
{
for (int i = 0; i < old; i++)
{
tmp[i] = _start[i];
}
delete _start;
}
_start = tmp;
_finish = _start + old;
_endofstorage = _start + n;
}
}
void resize(size_t n, T val = T())
{
if (n > size())
{
reserve(n);
while (_finish < _start + n)
{
*_finish = val;
++_finish;
}
}
else
{
_finish = _start + n;
}
}
reserve :如果需要修改的容量大于之前的空间,就需要扩容,如果不需要扩容的话,reserve函数则什么都不需要做, 扩容的过程中,先开辟新的空间,再把之前的数据拷贝到新空间,最后调整成员变量的值就可以完成扩容
如果本身开始什么都没有 if ( _start) 那么就直接将新空间当作自己的就可以 不需要拷贝,否则需要拷贝之前的值
resize :resize函数的功能区别与reserve,如果 n<size( ) 则需要把多余的值清空,只需要把_finish 往前移动就可以覆盖掉需要清除的值,如果 n > size( ) 的话,则直接调用reserve( )去扩容,然后将多余的空间初始化成 val
构造函数
vector()
{
}
如果传参数的话构造函数我们什么都不需要做
vector(size_t n, const T& val = T())
{
resize(n, val);
}
与STL::vector 一样,需要初始化成容量为n,并且vector里的值全部设为val
所以这里我们可以直接复用resize( )
拷贝构造
operator =
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endofstorage, v._endofstorage);
}
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
由于函数传值传参会拷贝实参 所以这里我们直接将传过来的形参与原vector进行交换操作
等出了函数作用与,形参销毁,就顺手把我们原来的数据一起调用析构函数清理了
拷贝构造
vector(const vector<T>& V)
{
reserve(V.capacity());
for (const auto& e : V)
{
push_back(e);
}
}
直接复用reserve 来设置并开辟空间大小,然后将要拷贝的向量中的值拷贝到自己的空间中,这样就完成了拷贝构造
析构函数
~vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _endofstorage = nullptr;
}
}
跟reserve一样,如果本身就没有开辟空间(_start 默认为nullptr)本身不用销毁
如果开辟了空间,就直接将_start指向的空间进行 delete
并且把成员变量全部赋成nullptr
添加元素
push_back()
void push_back(const T& x)
{
if (_finish == _endofstorage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;//扩二倍
reserve(newcapacity);
}
*_finish = x;
_finish++;
}
判断容量:
首先判断空间有没有被用完,只用判断_finish 与 _endofstorage 的位置是不是指向同一个
分两种情况
1.如果本身原先为空的vector ,那么开4个空间,
2.如果本身不是空的vector ,就把旧的空间大小扩大二倍
然后复用reverse()完成扩容
然后将_finish 位置的空间设置成需要修改的值就可以了
insert( )
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
if (_finish == _endofstorage)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;
}
//memmove(pos + 1, pos, sizeof(T) * (_finish - pos));
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos;
}
首先 判断迭代器有没有越界,然后 判断容量,然后 挪动旧元素,将腾出来的位置设置成要修改的值
push_back( )可以复用insert()只需要把pos传成end( )即可
删除元素
pop_back( )
void pop_back()
{
--_finish;
}
删除最后一个元素不需要进行任何容量操作,只需要将_finish 指针向前移动,把最后一个元素覆盖即可完成删除
erase( )
iterator erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator it = pos + 1;
while (it < _finish)
{
*(it - 1) = *it;
++it;
}
_finish--;
return pos;
}
1.先判断pos的位置合不合法,会不会越界(这里直接暴力断言)
2.将pos后边的元素依次向前挪动,即可完成删除
pop_back( )可以复用erase( )只需要将pos传成end( )-1即可