(一)什么是vector?
vector是C++标准模板库中的部分内容,中文偶尔译作“容器”,但并不准确。它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。
它的底层是由双端队列数据结构实现的。其内部成员实际上是start、finish和endofstorage三个指针构成,起始指针为start,而finish指向最后一个数据,也就是size大小就为finish-start,endofstorage是指向空间的最后一位,也就是capacity大小就为endofstorage-start;
(二)vector常用接口及实现
//vector构造函数
vector()
:_start(nullptr)
,_finish(nullptr)
,_endofstoage(nullptr)
{}
//拷贝构造
//比如要开名为v的5个1的空间则定义为vector v(5,1);
vector(int n, const T& value = T())
:_start(nullptr)
, _finish(nullptr)
, _endofstoage(nullptr)
{
reserve(n);
while (n--)
{
push_back(value);
}
}
template<class InputIterator>
//拷贝构造函数:传入原vector类型的_fist和_finish;
//比如要开一个V2,和V1一样大小的空间,则v2(v1.begin(),v1.end());
vector(InputIterator first, InputIterator last)
:_start(nullptr)
, _finish(nullptr)
, _endofstoage(nullptr)
{
reserve(last - first);
while (first != last)
{
push_back(*first);
first++;
}
}
//v2(v1);
vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _endofstoage(nullptr)
{
vector<T> temp(v.begin(), v.end());
swap(temp);
}
//析构函数
~vector()
{
delete[] _start;
_start = _finish = _endofstorage = nullptr;
}
// capacity
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endofstoage - _start;
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* temp = new T[n];
if (_start)
{
for (size_t i = 0; i < sz; ++i)
{
temp[i] = _start[i];
}
}
_start = temp;
_finish = _start + sz;
_endofstoage = _start + n;
}
}
void resize(size_t n, const T& value = T())
{
if (n > capacity())
{
reserve(n);
}
if (n < size())
{
_finish = _start + n;
}
else
{
while (_finish != _start + n)
{
*_finish = value;
++_finish;
}
}
}
void check_capacity()
{
if (_finish == _endofstoage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newcapacity);
}
}
void push_back(const T& x)
{
check_capacity();
*_finish = x;
++_finish;
}
void pop_back()
{
assert(_finish > _start);
--_finish;
}
void swap(vector<T>& v)
{
std::swap( v._start);
std::swap(v._finish);
std::swap(v._endofstorage);
}
iterator insert(iterator pos, const T& x)
{
assert(pos <= _finish&&pos >= _start)
size_t oldpos = pos - _start;
check_capacity();
pos = _start + oldpos;
T* end = _finish-1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos;
}
iterator erase(Iterator pos)
{
assert(pos <= _finish&&pos >= _start)
iterator it = pos + 1;
while (it != _finish)
{
*(it - 1) = *it;
}
--_finish;
return pos;
}
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const
{
assert(pos < size());
return _start[pos];
}
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator cbegin() const
{
return _start;
}
const_iterator cend() const
{
return _finish;
}
1.迭代器失效问题
vector的插入操作如果导致底层空间重新开辟,则迭代器就会失效,但容量多余的前提下插入数据,迭代器不失效。
vector删除,当前元素肯定失效,后面元素会牵扯到移动数据,因此删除元素后面的迭代器也会失效
2.使用memcpy拷贝问题
当我们模拟vector中reserve函数时,使用memcpy进行的拷贝时,如果vector定义的是自定义类型,它实际上是浅拷贝。就会造成崩溃。
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
memcpy(tmp, _start, sizeof(T)*size());
delete[] _start;
_start = tmp;
_finish = _start + sz;
_endofstorage = _start + n;
}
}
- memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中。
- 如果拷贝的是自定义类型的元素,memcpy即高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。