目录
一、整体框架
二、构造和析构函数
1.无参构造
2.迭代器区间构造
3.拷贝构造
4.赋值
5.析构
三、大小和容量相关函数
1.大小和容量
2.reserve
3.resize
四、插入和删除
1.尾插
2.尾删
3.插入
4.删除
template
class vector
{
public:
// Vector的迭代器是一个原生指针
typedef T* iterator;
typedef const T* const_iterator;
iterator begin();
iterator end();
const_iterator cbegin() const;
const_iterator cend() const;
// construct and destroy
vector();
vector(int n, const T& value = T());
template
vector(InputIterator first, InputIterator last);
vector(const vector& v);
vector& operator= (vector v);
~vector();
// capacity
size_t size() const;
size_t capacity() const;
void reserve(size_t n);
void resize(size_t n, const T& value = T());
///access///
T& operator[](size_t pos);
const T& operator[](size_t pos) const;
///modify/
void push_back(const T& x);
void pop_back();
void swap(vector& v);
iterator insert(iterator pos, const T& x);
iterator erase(iterator pos);
private:
iterator _start; // 指向数据块的开始
iterator _finish; // 指向有效数据的尾
iterator _endOfStorage; // 指向存储容量的尾
};
将三个指针置空即可。
vector()
: _start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{}
复用尾插函数,遍历迭代器范围。
template
vector(InputIterator first, InputIterator last)
:_start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
for (InputIterator it = first; it != last; it++)
{
push_back(*it);
}
}
利用迭代器区间构造临时的变量,与临时变量交换即可完成拷贝构造。也可以重新开空间,再进行内容的拷贝,但明显以下写法更好。
vector(const vector& v)
: _start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
vector temp(v.cbegin(), v.cend());
swap(temp);
}
交换函数内容如下,交换两个实例中的指针内容。
void swap(vector& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endOfStorage, v._endOfStorage);
}
赋值可复用参数传递中的拷贝构造,交换内部的指针即可完成赋值。
vector& operator= (vector v)
{
swap(v);
return *this;
}
释放空间,指针置空。
~vector()
{
delete[] _start;
_start = nullptr;
_finish = nullptr;
_endOfStorage = nullptr;
}
返回大小或容量,利用指针相减即可。
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endOfStorage - _start;
}
传入参数大于当前容量就会增容,不大于当前容量不会操作。
由于增容需要开辟新的空间,原来的指针指向原来的空间,因此需要提前记录指针的相对位置,保证新空间的指针正确。同时在旧的内容拷贝上不要使用memcopy浅拷贝,否则在容器存放内置类型的数据时会导致多次析构出错。
void reserve(size_t n)
{
if (n > capacity())
{
size_t size = _finish - _start;
T* temp = new T[n];
if (_start)
{
for (int i = 0; i < size; i++)
{
temp[i] = _start[i];
}
delete[] _start;
}
_start = temp;
_finish = _start + size;
_endOfStorage = _start + n;
}
}
传入参数大于当前数据个数,对原有数据不改变,多出来的部分会初始化。如果大于当前容量,则先增容再初始化。小于当前数据个数,则会对数据进行截断。
void resize(size_t n, const T& value = T())
{
if (n > size())
{
reserve(n);
while (_finish != _start + n)
{
*_finish = value;
_finish++;
}
}
else
{
_finish = _start + n;
}
}
使用_finish指针操作即可,再扩容时如果容量为0,应给一个起始容量。
void push_back(const T& x)
{
if (_finish == _endOfStorage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
_finish++;
}
需要保证不会在容器为空的情况下尾删。
void pop_back()
{
assert(_finish > _start);
_finish--;
}
利用指针,移位数据,再将新数据插入。要考虑移位的方向会不会数据的覆盖,导致数据丢失。
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _endOfStorage)
{
size_t sz = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + sz;
}
iterator it = _finish - 1;
while (it != pos)
{
*(it + 1) = *it;
it--;
}
*pos = x;
_finish++;
return pos;
}
同上,用指针对数据移位,覆盖删除的位置。
iterator erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator it = pos+1;
while (it != _finish)
{
*(it-1) = *it;
it++;
}
_finish--;
return pos;
}