1.vector的介绍及使用
1.1 vector的介绍
可以通过以下链接了解vector:cplusplus.com/reference/vector/vector/
使用STL的三个境界:能用,明理,能拓展。
1.2 vector的使用
1.2.1 vector的重点接口
构造函数声明 | 接口说明 |
vector() | 无参构造 |
vector(const vector&x) | 拷贝构造 |
1.2.2 vector iterator的使用
iterator的使用 | 接口说明 |
begin+end | 获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下 一个位置的iterator/const_iterator |
rbegin+rend | 获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置 的reverse_iterator |
1.2.3 vector 空间增长问题
容量空间 | 接口说明 |
size | 获取数据个数 |
capacity | 获取容量大小 |
empty | 判断是否为空 |
resize | 改变vector的size |
reserve | 改变vector的capacity |
注意:1.在vs下capacity是按1.5倍增长的,g++是按2倍增长的。
2.reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价。
3.resize在空间的同时还会进行初始化,影响size。
1.2.4 vector 增删查改
vector增删查改 | 接口说明 |
push back | 尾插 |
pop back | 尾删 |
find | 查找(算法模块生成的,不是vector的成员接口) |
insert | 在position之前插入val |
erase | 删除position位置的数据 |
swap | 交换两个vector的数据空间 |
operator[] | 像数组一样访问 |
1.2.5 vector迭代器失效问题
迭代器的主要作用就是让算法能够不用关心底层数据,其底层实际就是一个指针,或者是对指针进行封装。
对于vector肯会导致其迭代器失效的操作有:
1.会引起底层空间改变的操作,都有可能是迭代器失效。如:resize,reserve,insert,assign,push_back等。
2.指定位置元素的删除操作:erase
3.注意:linux下,编译器对迭代器的失效的检查不是很严格。
4.与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效。
迭代器失效的解决办法:在使用前,对迭代器重新赋值即可。
2.vector深度剖析及模拟实现
2.1 std::vector的核心框架接口的模拟实现
#include<iostream>
using namespcae std;
#include<assert.h>
namespace vet
{
template<class T>
class vector
{
public://vector的迭代器是原生指针
typedef T* iterator;
typedef const T* const_iterator;
//构造和销毁
vector()
: _start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{}
vector(size_t n, const T& value = T())
: _start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
reserve(n);
while (n--)
{
push_back(value);
}
}
//理论上,提供了vector(size_t n,const T& value = T())之后
vector(int n,const T& value = T())就不需要提供了,但对于vector<int> v(10,5);
编译器在编译时,认为T已经实例化为int,而10和5的类型都为int就会走vector(InputIterator first,InputIterator last),但(10,5)根本不是一个区间,所以会编译报错,所以需要增加构造方法
vector(int n, const T& value = T())
: _start(new T[n])
, _finish(_start+n)
, _endOfStorage(_finish)
{
for (int i = 0; i < n; ++i)
{
_start[i] = value;
}
}
//如果使用iterator做迭代器,会导致初始化迭代器区间[first,last)只能是vector的迭代器//重新声明迭代器,迭代器区间(first,last)可以是任意容器的迭代器
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector(const vector<T>& v)
: _start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
reserve(v.capacity());
iterator it = begin();
const_iterator vit = v.cbegin();
while (vit != v.cend())
{
*it++ = *vit++;
}
_finish = it;
}
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
~vector()
{
if(_start)
{
delete[] _start;
_start=_finish=_endOfStorage = nullptr;
}
}
//迭代器相关
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator cbegin() const
{
return _start;}
const_iterator cend() const
{
return _finish;}
//容量相关
size_t size() const
{
return _finish - _start;}
size_t capacity() const
{
return _endOfStorage - _start;}
bool empty() const
{
return _start = _finish;
}
void reserve(size_t n)
{
size_t oldsize = size();T*tmp = new T[n];
if(_start)
{
for(int i =0;i<oldsize;i++){
tmp[i] = _start[i];
}
delete[] _start;
}
_start = _tmp;
_finish = _start +oldsize;
_endOfStorage = _start +n;
}
}
void resize(size_t n,const T& value = T())
{
// 1.如果n小于当前的size,则数据个数缩小到n
if(n<=size()){
_finish = _start + n;
return;
}
// 2.空间不够则增容
if(n>capacity())
{
reserve(n);}
// 3.将size扩大到n
iterator it = _finish;
_finish = _start + n;
while (it != _finish)
{
*it = value;
++it;
}
}
//元素访问
//后面的const修饰this指针,表示函数内不能修改成员变量
const T&operator(size_t pos)const
{
assert(pos<size());
return _start(pos);
}
const T& front()const
{
return *_start;
}
const T&back()const
//vector的修改操作
void push_back(const T&x)
{
insert(end(),x);
}
void pop_back(const T&x)
{
erase(end()-1);}
void swap(vector<T>& v)
{
std::swap(_start,v._start);
std::swap(_finish,v._finish);
std::swap(_endOfStorage,v._endOfStorage);
}
iterator insert(iterator pos, const T& x)
{
assert(pos <= _finish);
// 空间不够先进行增容
if (_finish == _endOfStorage)
{
/ /size_t size = size();
size_t newCapacity = (0 == capacity()) ? 1 : capacity() * 2;
reserve(newCapacity);
// 如果发生了增容,需要重置pos
pos = _start + size();
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos;
}
interator erase(iterator pos)
{
interator begin = pos+1;
while(begin !=_finish)
{
*(begin-1) = *begin;
++begin;
}
--finish;
return pos;
}
private:
iterator _start; // 指向数据块的开始
iterator _finish; // 指向有效数据的尾
iterator _endOfStorage; // 指向存储容量的尾
};
}
2.2 使用memcpy拷贝问题
如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则会引起内存泄漏甚至程序崩溃。
2.3动态二维数组理解
// 以杨慧三角的前n行为例:假设n为5void test2vector(size_t n){// 使用vector定义二维数组vv,vv中的每个元素都是vector<int>bit::vector<bit::vector<int>> vv(n);// 将二维数组每一行中的vecotr<int>中的元素全部设置为1for (size_t i = 0; i < n; ++i)vv[i].resize(i + 1, 1);// 给杨慧三角出第一列和对角线的所有元素赋值for (int i = 2; i < n; ++i){for (int j = 1; j < i; ++j){vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];}}}