在之前的文章模拟实现源码剖析了STL中的List,这篇文章模拟STL中的vector.
模拟实现STL中的list
《STL源码剖析》中对vector的描述是这样的:
vector的数据安排以及操作方式,与array非常相似。两者的唯一区别在于空间运用的灵活性。array是静态空间,一旦配置了就不能改变。vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。
vector的实现技术,关键在于其对大小的控制以及重新分配时的数据移动效率。
vector的迭代器是普通指针
vector维护的是一个线性连续空间,所以不论其元素类型是什么,普通指针都可以作为vector的迭代器而满足所有必要条件,因为vector所需要的操作行为,如operator*,operator->,operator++,operator–等,普通指针天生就具备,vector支持随机存取,而普通指针正有着这样的能力。
#include<iostream>
#include<assert.h>
using namespace std;
template<class T>
class Vector
{
protected:
typedef T* Iterator;
typedef const T* ConstIterator;
public:
Vector()
:_start(NULL)
, _finish(NULL)
, _endofstorage(NULL)
{}
Vector<T>&operator = (Vector<T>&v)
{
if (_start != v._start)
{
swap(_start, v._start);
swap(_finsh, v._finsh);
swap(_EndOfStorage, v._EndOfStorage);
}
return *this;
}
Vector(const Vector<T>& v)
:_start(NULL)
, _finish(NULL)
, _endofstorage(NULL)
{
size_t size = Size();
size_t capacity = Capacity();
T* tmp = new T[capacity];
if (_start)
{
for (size_t i; i < Size(); ++i)
{
tmp[i] = v._start[i];
}
delete[] _start;
}
_start = tmp;
_finish = v._finish;
_endofstorage = v._endofstorage;
}
//随机插入
void Insert(Iterator pos, const T& x)
{
if (_finish == _endofstorage)
{
_Expand(Capacity() * 2 + 3);
}
for (Iterator tmp = End(); tmp != pos; tmp--)
{
*tmp = *(tmp - 1);
}
*pos = x;
_finish++;
}
//随机删除
void Erase(Iterator pos)
{
Iterator end = End();
for (Iterator tmp = pos; tmp != --end; ++tmp)
{
*tmp = *(tmp + 1);
}
--_finish;
}
//改变容量
void Reserve(size_t n)
{
assert(n > 0);
if (n > Capacity())
{
_Expand(n);//扩容
}
}
//改变元素个数
void Resize(size_t n, const T& x = 0)
{
size_t size = Size();
size_t capacity = Capacity();
if (n > Capacity())
{
_Expand(n);
for (size_t i = 0; i <= n-size; ++i)
{
Insert(Begin()+size+i, x);
}
}
else if (n > Size())
{
for (size_t i = 0; i <= n-size; ++i)
{
Insert(Begin()+size+i, x);
}
}
else if (n < size)
{
_finish = _start + n;
}
}
void PushBack(const T& x)
{
if (_finish == _endofstorage)
{
_Expand(Capacity() * 2 + 3);
}
Insert(End(), x);
}
void PopBack()
{
Iterator end = End();
Erase(--end);
}
Iterator Begin()
{
return _start;
}
Iterator End()
{
return _finish;
}
size_t Size()
{
return (End() - Begin());
}
size_t Capacity()
{
return (_endofstorage - _start);
}
bool Empty()
{
return _start == _finish;
}
//要支持[]
T& operator[](size_t n)
{
return _start + n;
}
T& Front()const
{
return *Begin();
}
T& Back()const
{
return *End();
}
void Print()
{
for (size_t i = 0; i < Size(); i++)
{
cout << _start[i] << " ";
}
cout << endl;
}
protected:
void _Expand(size_t n)
{
assert(n > 0);
assert(n > Capacity());
T* tmp = new T[n];
if (_start)
{
for (size_t i = 0; i < Size(); ++i)
{
tmp[i] = _start[i];
}
delete[] _start;
}
size_t size = Size();
_start = tmp;
_finish = _start + size;
_endofstorage = _start + n;
}
protected:
Iterator _start;//表示目前使用空间的头
Iterator _finish;//表示目前使用空间的尾
Iterator _endofstorage;//表示目前可用空间的尾
};
void Test()
{
Vector<int> v;
v.PushBack(1);
v.PushBack(2);
v.PushBack(3);
v.PushBack(4);
v.PushBack(5);
v.Resize(8,6);
//v.Reserve(10);
//v.PopBack();
v.Print();
}
在STL中resize()函数的作用是改变vector元素的个数:
主要有三层含义:
1:如果n比vector容器的size小,结果size减小到n,然后删除n之后的数据。
2:如果n比vector容器的size大,扩展空间,然后在size后面插入元素并且初始化,否则初始化为缺省值。
3:如果n比vector容器的capacity还要大,自动进行内存分配。
在STL中reserve()的作用是改变容量:
1:如果n的大小比vector的容量大,开空间增容到n
2:其他的情况,没有开空间,vetor的容量不受影响。而且size的值没有变化。
当然使用reserve的优点是减少开销。
总结resize()函数时改变数组的个数并对其初始化,而reserve()函数只是改变容量。