vector<vector> 会实例化两个类
看源代码不能一行一行看
有了模板之后,内置类型也需要有默认构造函数,所以可以认为内置类型有默认构造函数
迭代器引用不能
insert之后迭代器失效,有可能野指针
erase之后迭代器失效,结果未定义
匿名对象生命周期只在一行,const&可以延迟生命周期
- 了解vector容器
- 熟悉vector的常见接口
- 常见接口的模拟实现
了解vector容器
1.vector容器
vector是C++标准模板库中的部分内容,vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。
- vector内部可以存放内置类型,也可以存放自定义类型。如int,string等
2.vector和string的区别与联系
- vector可以存放任意类型的对象,而string只存放char类型的对象
- vector的接口比之string接口更为通用,string的某些接口设计是为了更好的操作串
- vector和string底层空间都是连续的,本质上都是数组和方法的封装。
3.vector中迭代器
由于底层空间连续,所以原生指针可以作为迭代器使用,同样也可以封装为一个类。VS用的P.J.版本就将string的迭代器封装为一个类,g++用的SGI版本的string迭代器是原生指针。这里模拟实现原生指针版本的。
迭代器失效问题:
vector的迭代器失效常见于insert和erase之后,库中对于insert和erase的函数声明:iterator insert (iterator position, const value_type& val);
iterator erase (iterator position);
(注:这里只给出一个函数重载版本,详见下面)
- insert迭代器失效:这里可以看到函数参数为迭代器类型
iterator
,position为原生指针,插入一个数据之后,如果空间扩容,那么position的位置必会更改,此时在insert之后使用原来的position就会造成野指针问题。 - erase迭代器失效:如果erase的对象是最后一个元素的话,在源程序中继续使用position,则会
如上,string的insert和erase也会有迭代器失效问题,只是在string中insert和erase函数参数position
一般用size_t
下标,不用迭代器,故不会出现迭代器失效问题,当然string的insert和erase函数也有迭代器的重载版本,如果用迭代器进行insert和erase,也会出现失效问题。
解决迭代器失效办法:
在每次insert和erase之后,及时更新position,即用函数返回值来更新。但更为建议的是:统一认为insert和erase之后迭代器失效了,不应该使用了。
vector常见接口
std库中vector的声明:template < class T, class Alloc = allocator<T> > class vector;
- T:数据类型
- Alloc:。。。。
一.构造
vector();
- 默认构造函数
vector(size_t n, const T& val = T());
- 构造有n个val的vector
vector(const vector& v);
- 拷贝构造
template<class InputIterator> vector(InputIterator first, InputIterator last);
- [first, last) 迭代器区间构造
- [first, last) 迭代器区间构造
二.运算符重载
vector& operator= (const vector& x);
- 赋值重载
T& operator[](size_t pos);
- 方括号重载
- 方括号重载
三.容量相关
size_t size() const;
- 有效元素个数
size_t capacity() const;
- 容器容量
void resize(size_t n, const T& val = T());
- 如果n>capacity(),则扩容并且用val填充空间
- 如果n<capacity()且n>size(), 则用val填充空间
- 如果n<capacity()且n<size(), 则会减少size到n
void reserve(size_t n);
- n>capacity() ,则扩容,若小于capacity,不变
bool empty() const;
- vector为空返回true
- vector不为空返回false
四.元素操作相关
iterator insert(iterator position, const T& val);
- 在position插入val
iterator insert(iterator position, size_t n, const T& val);
- 在position插入n个val
iterator erase(iterator position);
- 删除position位置元素
void push_back(const T& val);
- 尾插val
void pop_back();
- 尾删
void swap(vector& v);
- 交换两个vector
- 交换两个vector
五.迭代器
iterator begin();
- 返回迭代器起始位置
const_iterator begin() const;
- 返回const迭代器起始位置
iterator end();
- 返回迭代器最后一个元素下一个位置
const_iterator end() const;
- 返回const迭代器最后一个元素下一个位置
- 返回const迭代器最后一个元素下一个位置
接口模拟实现
namespace zs
{
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
//如果你提供了构造函数,默认构造函数不在给出
vector()
{}
//在模板中,认为内置类型有默认构造函数,这里由于有一个类模板,防止
//编译器匹配错误,所以需要重载一个相同参数类型的版本
vector(size_t n, const T& val = T())
{
_begin = new T[n];
_finish = _begin + n;
_end_of_storage = _begin + n;
size_t i = 0;
for (; i < n; ++i)
{
_begin[i] = val;
}
}
vector(int n, const T& val = T())
{
_begin = new T[n];
_finish = _begin + n;
_end_of_storage = _begin + n;
size_t i = 0;
for (; i < n; ++i)
{
_begin[i] = val;
}
}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector(const vector<T>& v)
{
reserve(v.capacity());
//不能用memcpy,如果T是自定义类型的话会出错
size_t i = 0;
while (i < v.size())
{
_begin[i] = v._begin[i];
++i;
}
_finish = _begin + v.size();
_end_of_storage = _begin + v.capacity();
}
T& operator[](size_t pos)
{
assert(pos >= 0);
assert(pos < size());
return *(_begin + pos);
}
const T& operator[](size_t pos) const
{
assert(pos >= 0);
assert(pos < size());
return *(_begin + pos);
}
iterator insert(iterator pos, const T& val)
{
assert(pos >= _begin);
assert(pos <= _finish);
if (size() + 1 > capacity())
{
size_t len = pos - _begin;
reserve(2 * (capacity() == 0 ? 4 : capacity()));
pos = _begin + len;
}
iterator cur = _finish-1;
while (pos <= cur)
{
*(cur + 1) = *(cur);
--cur;
}
*pos = val;
++_finish;
return pos;
}
iterator erase(iterator pos)
{
assert(pos >= _begin);
assert(pos < _finish);
iterator cur = pos + 1;
while (cur != _finish)
{
*(cur-1) = *(cur);
++cur;
}
--_finish;
return pos;
}
void push_back(const T& val)
{
if (size() + 1 > capacity())
{
reserve(2 * (capacity() == 0 ? 4 : capacity()));
}
*_finish = val;
++_finish;
}
void pop_back()
{
assert(!empty());
--_finish;
}
bool empty() const
{
return _begin == _finish;
}
vector<T>& operator=(vector<T> v)
{
std::swap(_begin, v._begin);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
return *this;
}
void resize(size_t n, const T& val)
{
if (n < size())
{
_finish = _begin + n;
}
else if (n > size())
{
if (n > capacity())
{
reserve(n);
}
while (_finish != _begin + n)
{
*_finish = val;
++_finish;
}
}
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_begin != nullptr)
{
size_t i = 0;
while (i < n)
{
tmp[i] = _begin[i];
++i;
}
delete[] _begin;
}
_begin = tmp;
_finish = _begin + sz;
_end_of_storage = _begin + n;
}
}
size_t size() const
{
return _finish - _begin;
}
size_t capacity() const
{
return _end_of_storage - _begin;
}
iterator begin()
{
return _begin;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _begin;
}
const_iterator end() const
{
return _finish;
}
~vector()
{
delete[] _begin;
_begin = _finish = _end_of_storage = nullptr;
}
private:
iterator _begin = nullptr; //起始地址
iterator _finish = nullptr; //最后一个有效数据的下一个位置
iterator _end_of_storage = nullptr; //存储空间末尾的下一个位置
};
}