一、基本概念
- vector是表示可变大小的数组的容器
- vector是连续存储空间来存储元素的,并且是动态的(如果需要扩容/缩容的话,不是在原来空间的后面增加空间,而是找另一块空间,将原来空间的内容拷贝回去,释放原来的空间)
- vector容器在头文件 < vector >中
二、成员变量
vector是用三个指针来维护的
start:指向空间的开头
finish:指向有效数据的尾
endOfStorage:指向存储空间的尾
三、重要接口
3.1 构造函数
默认构造 | vector () |
---|---|
构造并初始化n个value | vector(n,value) |
拷贝构造 | vector(const vector& v) |
迭代器区间构造 | vector(InputIterator first,InputIterator last) |
代码演示
void printVector(vector<int>& v)
{ //利用迭代器打印 v
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
vector<int> v; //默认构造
vector<int> v1(10, 1); //构造10个1
vector<int> v2(v1.begin(), v1.end()); //利用v1的迭代器区间构造
vector<int> v3(v2); //拷贝构造
printVector(v);
printVector(v1);
printVector(v2);
printVector(v3);
return 0;
}
3.2 iterator
vector的iterator可以简单的理解成指针。
begin() | 返回第一个数据位置的iterator |
---|---|
end() | 返回最后一个数据位置的后一个 的iterator |
rbegin() | 返回最后一个数据位置的iterator |
rend() | 返回第一个数据位置的前一个的iterator |
void PrintVector(const vector<int>& v)
{
// const对象使用const迭代器进行遍历打印
vector<int>::const_iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
void main()
{
// 使用push_back插入4个数据
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
// 使用迭代器进行遍历打印
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
// 使用迭代器进行修改
it = v.begin();
while (it != v.end())
{
*it *= 2;
++it;
}
// 使用反向迭代器进行遍历再打印
// vector<int>::reverse_iterator rit = v.rbegin();
auto rit = v.rbegin();
while (rit != v.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
PrintVector(v);
}
3.3 容量和大小
size | 返回数据元素的个数 |
---|---|
capacity | 返回容量的大小 |
empty | 返回是否为空 |
resize(n) | 改变容器的size |
reserve(n) | 改变容器的capacity |
注:
- resize第二个参数是缺省参数,如果没传,就默认调用构造函数
- 如果resize的n大于size的大小,那么后面的位置会填充你传的数据,如果没传就填充默认数据
- 如果resize的n小于size的大小,发生截断
- reserve扩容规则在不同编译器下是不同的,vs下capacity是按1.5倍增长的,g++是按2倍增长的
代码演示
int main()
{
vector<int> v;
// set some initial content:
for (int i = 1; i < 10; i++)
v.push_back(i);
v.resize(5);
v.resize(8, 100);
v.resize(12);
cout << "v contains:";
for (size_t i = 0; i < v.size(); i++)
cout << ' ' << v[i];
cout << '\n';
return 0;
}
3.4 增删查改
push_back(num) | 尾插数据 |
---|---|
pop_back() | 尾删数据 |
insert(pos,num) | 在pos位置前插入数据 |
insert(pos,size,num) | 在pos位置前插入size个数据 |
erase(pos) | 删除pos位置的数据 |
erase (begin,end) | 删除begin~end区间的数据 |
clear() | 清理所有数据 |
operator[ ] | 像数组一样访问数据 |
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
auto it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
v.pop_back();
v.pop_back();
it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
四、迭代器失效
迭代器失效的本质就是指向了一块已经被释放的空间(野指针),那什么情况会导致这个问题呢?很明显就是在扩容和缩容的时候,一些接口比如:resize、reserve、insert、assign、push_back都会导致底层空间的改变,导致迭代器失效。
代码演示
int main()
{
int a[] = { 1, 2, 3, 4 };
vector<int> v(a, a + sizeof(a) / sizeof(int));
// 使用find查找3所在位置的iterator
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
// 删除pos位置的数据,导致pos迭代器失效。
v.erase(pos);
cout << *pos << endl; // 此处会导致非法访问
return 0;
}
erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。